Re: [Tutor] class functions/staticmethod?

2019-08-13 Thread Cameron Simpson

On 14Aug2019 11:15, Steven D'Aprano  wrote:

On Wed, Aug 14, 2019 at 09:58:35AM +1000, Cameron Simpson wrote:

On 11Aug2019 22:58, James Hartley  wrote:
>I am lacking in understanding of the @staticmethod property.
>Explanation(s)/links might be helpful.  I have not found the descriptions
>found in the Internet wild to be particularly instructive.

You have received some answers; to me they seem detailed enough to be
confusing.


Its only confusing if you don't work your way through it carefully and
systematically. There's a lot to understand, but if you don't understand
it, Python's behaviour in this case seems counter-intuitive and hard to
follow.


Yeah, but it helps to understand the objective: function context.

A deep dive into the mechanisms used to achieve that is a load to 
ingest. High levels of detail tend to swamp one's view of the larger 
picture, particularly when learning.


[...]

I think of things this way: what context does a method require?  Not
everything needs the calling instance.

Here endeth the lesson.


Given that you go on to write almost another 150 lines of explanation, I
think a better description would be "Here *begins* the lesson" *wink*


Well, maybe, but I really wanted to highlight the objective: 
@classmethod and @staticmethod dictate the context provided to the 
method.


All the examples that follow aim, however vaguely, to show those 
contexts in action.



Your lesson, I think, assumes that it is obvious that staticmethods
don't have access to the calling instance, or its class.


No, it aims to make that point clear. EVerything else is example or 
mechanism.



But if you look
at James' code, I think you will agree that he's assuming that
staticmethods *do* have access to the calling class, and is perplexed by
the fact that the look-up of class variables (class attributes) fails.


Because nobody had said that @staticmethod and @classmethod _define_ the 
provided context.



Your lesson gives us no clue why James' first method, "dimensions()",
which he describes as a "class method", isn't a class method and doesn't
actually work correctly, even though it appears to at first glance.


I didn't try to tackle his code. I think it is better to get the 
intended use of @classmethod and @staticmethod clear. Digging into 
whatever weird consequences there might be to his slightly wrong code 
just brings confusion.


Cheers,
Cameron Simpson 
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class functions/staticmethod?

2019-08-13 Thread Steven D'Aprano
On Wed, Aug 14, 2019 at 09:58:35AM +1000, Cameron Simpson wrote:
> On 11Aug2019 22:58, James Hartley  wrote:
> >I am lacking in understanding of the @staticmethod property.
> >Explanation(s)/links might be helpful.  I have not found the descriptions
> >found in the Internet wild to be particularly instructive.
> 
> You have received some answers; to me they seem detailed enough to be 
> confusing.

Its only confusing if you don't work your way through it carefully and 
systematically. There's a lot to understand, but if you don't understand 
it, Python's behaviour in this case seems counter-intuitive and hard to 
follow.

Python makes the behaviour of regular instance methods so simple and 
intuitive, it can be quite a blow when you try to do something that 
isn't.


> I think of things this way: what context does a method require?  Not 
> everything needs the calling instance.
> 
> Here endeth the lesson.

Given that you go on to write almost another 150 lines of explanation, I 
think a better description would be "Here *begins* the lesson" *wink*


Your lesson, I think, assumes that it is obvious that staticmethods 
don't have access to the calling instance, or its class. But if you look 
at James' code, I think you will agree that he's assuming that 
staticmethods *do* have access to the calling class, and is perplexed by 
the fact that the look-up of class variables (class attributes) fails.

If James comes from a Java background, he's probably assuming that 
static methods do have access to the class variables, using undotted 
names:

class K(object):
attr = 1
@staticmethod
def foo():
return attr

In Java, K.foo() would return 1.

Your lesson gives us no clue why James' first method, "dimensions()", 
which he describes as a "class method", isn't a class method and doesn't 
actually work correctly, even though it appears to at first glance.


-- 
Steven
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class functions/staticmethod?

2019-08-13 Thread Cameron Simpson

On 11Aug2019 22:58, James Hartley  wrote:

I am lacking in understanding of the @staticmethod property.
Explanation(s)/links might be helpful.  I have not found the descriptions
found in the Internet wild to be particularly instructive.


You have received some answers; to me they seem detailed enough to be 
confusing.


I think of things this way: what context does a method require?  Not 
everything needs the calling instance.


Here endeth the lesson.



All this stuff below is examples based on that criterion:

Here's a trite example class:

 class Rectangle:
   def __init__(self, width, height):
 self.width=width
 self.height = height

Most methods do things with self, and are thus "instance methods", the 
default. They automatically receive the instance used to call them as 
the first "self" argument.


 def area(self):
   return self.width * self.height

They need "self" as their context to do their work.

Some methods might not need an instance as context: perhaps they return 
information that is just based on the class, or they are factory methods 
intended to return a new instance of the class. Then you might use a 
@classmethod decorator to have the calling instance's class as the 
context.


 @classmethod
 def from_str(cls, s):
   width, height = parse_an_XxY_string(s)
   return cls(width, height)

And some methods do not need the class or the instance to do something 
useful:


 @staticmethod
 def compute_area(width, height):
   return width * height

and so we don't give them the instance or the class as context.

Now, _why_?

Instance methods are obvious enough - they exist to return values 
without the caller needing to know about the object internals.


Class methods are less obvious.

Consider that Python is a duck typed language: we try to arrange that 
provided an object has the right methods we can use various different 
types of objects with the same functions. For example:


 def total_area(flat_things):
   return sum(flat_thing.area() for flat_thing in flat_things)

That will work for Rectangles and also other things with .area() 
methods. Area, though, is an instance method.


Class methods tend to come into their own with subclassing: I 
particularly use them for factory methods.


Supposing we have Rectangles and Ellipses, both subclasses of a 
FlatThing:


 class FlatThing:
   def __init__(self, width, height):
 self.width=width
 self.height = height
 @classmethod
 def from_str(cls, s):
   width, height = parse_an_XxY_string(s)
   return cls(width, height)

 class Rectangle(FlatThing):
   def area(self):
 return self.width * self.height

 class Ellipse(FlatThing):
   def area(self):
 return self.width * self.height * math.PI / 4

See that from_str? It is common to all the classes because they can all 
be characterised by their width and height. But I require the class for 
context in order to make a new object of the _correct_ class. Examples:


 rect = Rectangle.from_str("5x9")
 ellipse = Ellipse.from_str("5x9")
 ellispe2 = ellipse.from_str("6x7")

Here we make a Rectangle, and "cls" is Rectangle when you call it this 
way. Then we make an Ellipse, and "cls" is Ellipse when called this way.  
And then we make another Ellipse from the first ellipse, so "cls" is 
again "Ellipse" (because "ellipse" is an Ellipse).


You can see that regardless of how we call the factory function, the 
only context passed is the relevant class.


And in the last example (an Ellipse from an existing Ellipse), the class 
comes from the instance used to make the call. So we can write some 
function which DOES NOT KNOW whether it gets Ellipses or Rectangles:


 def bigger_things(flat_things):
   return [ flat_thing.from_str(
  "%sx%s" % (flat_thing.width*2, flat_thing.height*2))
for flat_thing in flat_things
  ]

Here we could pass in a mix if Rectangles or Ellipses (or anything else 
with a suitable from_str method) and get out a new list with a matching 
mix of bigger things.


Finally, the static method.

As Peter remarked, because a static method does not have the instance or 
class for context, it _could_ be written as an ordinary top level 
function.


Usually we use a static method in order to group top level functions 
_related_ to a specific class together. It also helps with imports 
elsewhere.


So consider the earlier:

 @staticmethod
 def compute_area(width, height):
   return width * height

in the Rectangle class. We _could_ just write this as a top level 
function outside the class:


 def compute_rectangular_area(width, height):
   return width * height

Now think about using that elsewhere:

 from flat_things_module import Rectangle, Ellipse, compute_rectangular_area

 area1 = compute_rectangular_area(5, 9)
 area2 = Rectangle.compute_area(5, 9)
 area3 = Ellipse.compute_area(5, 9)

I would rather use the forms of "area2" and "area3" because it is clear 
that I'm getting an area function from a nicely named class. (Also

Re: [Tutor] class functions/staticmethod?

2019-08-12 Thread Steven D'Aprano
Part 3.


On Sun, Aug 11, 2019 at 10:58:37PM -0500, James Hartley wrote:


> from collections import namedtuple
> 
> class Foo():
> Dimensions = namedtuple('Dimensions', ['height', 'width'])
> _dimensions = Dimensions(3, 4)
> 
> def dimensions():
> print('id = {}'.format(id(Foo._dimensions)))
> return Foo._dimensions
> 
> @staticmethod
> def dimensions1():
> print('id = {}'.format(id(_dimensions)))
> return _dimensions


In part 2, I explained that we can re-write the dimensions() method to 
work correctly using the @classmethod decorator:

@classmethod
def dimensions(cls):
print('id = {}'.format(id(cls._dimensions)))
return cls._dimensions


Another benefit of doing this is that it will now work correctly in 
subclasses.

class Bar(Foo):  # inherit from Foo
_dimensions = (3, 4, 5, 6)  # Override the parent's "dimensions".


Using your definition, Bar.dimensions() will return Foo._dimensions 
instead of Bar._dimensions. But using the classmethod version works as 
expected.

So why doesn't the staticmethod version work correctly? Its all to do 
with the way variable names are resolved by the interpreter.

If you are used to Java, for example, you might expect that "class 
variables" (what Python calls "class attributes") are part of the scope 
for methods:


spam = 999  # Global variable spam.

class MyClass(object):
 spam = 1  # Class attribute ("variable") spam.

 def method(self):
 return spam

instance = MyClass()


If you are used to Java's rules, you would expect that instance.method() 
will return 1, but in Python it returns the global spam, 999.

To simplify a little, the scoping rules for Python are described by the 
LEGB rule:

- Local variables have highest priority;
- followed by variables in the Enclosing function scope (if any);
- followed by Global variables;
- and lastly Builtins (like `len()`, `zip()`, etc).

Notice that the surrounding class isn't included.[1] To access either 
instance attributes or class attributes, you have to explicitly say so:

 def method(self):
 return self.spam

This is deliberate, and a FAQ:

https://docs.python.org/3/faq/design.html#why-must-self-be-used-explicitly-in-method-definitions-and-calls


Using Java's scoping rules, the staticmethod would have worked:

@staticmethod
def dimensions1():
print('id = {}'.format(id(_dimensions)))
return _dimensions

because it would see the _dimensions variable in the class scope. But 
Python doesn't work that way. You would have to grab hold of the class 
from the global scope, then grab dimensions:

@staticmethod
def dimensions1():
_dimensions = Foo._dimensions
print('id = {}'.format(id(_dimensions)))
return _dimensions


If you are coming from a Java background, you may have been fooled by an 
unfortunate clash in terminology. A "static method" in Java is closer to 
a *classmethod* in Python, not a staticmethod.

The main difference being that in Java, class variables (attributes) 
are automatically in scope; in Python you have to access them through 
the "cls" parameter.



-- 
Steven
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class functions/staticmethod?

2019-08-12 Thread Steven D'Aprano
Part Two.

On Sun, Aug 11, 2019 at 10:58:37PM -0500, James Hartley wrote:


> from collections import namedtuple
> 
> class Foo():
> Dimensions = namedtuple('Dimensions', ['height', 'width'])
> _dimensions = Dimensions(3, 4)
> 
> def dimensions():
> print('id = {}'.format(id(Foo._dimensions)))
> return Foo._dimensions
> 
> @staticmethod
> def dimensions1():
> print('id = {}'.format(id(_dimensions)))
> return _dimensions

> The class method Foo.dimensions() is capable of accessing class members,

Foo.dimensions is *not* a class method; it is a regular method that is 
written badly, and only works by accident.

It *seems* to be okay because when you try it like this:

Foo.dimensions()  # call directly from the class object

you bypass some of the method magic, and get access to the regular 
function object, which in turn does a global lookup by name to find 
"Foo" and everything works from that point (although a bit slower than 
necessary).

But it doesn't work properly, because if you try to use it like this:

Foo().dimensions()  # call from an instance

you'll get an error that the method takes no arguments but one is 
supplied.

To fix this, we can make it a proper classmethod like this:

class Foo():
Dimensions = namedtuple('Dimensions', ['height', 'width'])
_dimensions = Dimensions(3, 4)

@classmethod
def dimensions(cls):
print('id = {}'.format(id(cls._dimensions)))
return cls._dimensions


and now both Foo.dimensions() and Foo().dimensions() will work 
correctly, and as a bonus it ought to be a little faster.


Part 3 to follow.



-- 
Steven
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class functions/staticmethod?

2019-08-12 Thread Steven D'Aprano
On Sun, Aug 11, 2019 at 10:58:37PM -0500, James Hartley wrote:
> I am lacking in understanding of the @staticmethod property.
> Explanation(s)/links might be helpful.  I have not found the descriptions
> found in the Internet wild to be particularly instructive.  Given the code
> below:
[...]
> The class method Foo.dimensions() is capable of accessing class members,
> but Foo.dimensions1() cannot. What does the @staticmethod decorator really
> add?

Very little.

To understand staticmethod in Python, you have to understand what 
ordinary methods do.

When you make a class with a method:

class MyClass(object):
def spam(self):
print(self)


the interpreter creates a plain old regular function called "spam", and 
attaches it to MyClass. It is precisely the same as doing this:

def spam(self):
print(self)

class MyClass(object):
pass

MyClass.spam = spam

except more convenient. Methods are actually regular functions under 
the hood. But when you access a method, like this:

instance = MyClass()
instance.spam()  # call the method

the interpreter does some runtime magic to convert the function object 
into a method object which automatically knows what "self" is. This 
magic is called "the descriptor protocol", it's very clever but advanced 
programming, and the details aren't important here.

So just think of it like this:

When you access instance.spam, the interpreter converts the plain old 
dumb function object which has no idea what "self" is into a magical 
method object which does.

If you bypass the descriptor "magic", you can grab hold of the plain-old 
regular function:

py> instance = MyClass()
py> vars(type(instance))['spam']  # Bypass all the magic.


but it's dumb, and doesn't know what "self" is:

py> vars(type(instance))['spam']()
Traceback (most recent call last):
  File "", line 1, in 
TypeError: spam() missing 1 required positional argument: 'self'


If you use normal attribute access, the function is turned into a method 
object that knows what "self" should be:

py> instance.spam  # Normal access.
>

py> instance.spam()  # "self" is automatically provided
<__main__.MyClass object at 0xb77e52ac>


So that's how methods work normally. But what if you don't want a method 
that understands "self", but a regular dumb-old function, but for some 
reason it needs to be attached to a class?

You can't use a regular function in the class body, because it will be 
automatically turned into a method on access, and for some reason you 
don't want that. You need a way to tell the interpreter "Don't convert 
this into a method with self, leave it as a regular function", and 
staticmethod is that way.

(To be pedantic, it doesn't actually leave it as a regular function, it 
converts it to a staticmethod object which behaves like a regular 
function. But that's a difference which normally makes no difference.)

So you can see, the niche for staticmethod is very, very narrow. You 
need something that is attached to a class, which you can call like a 
method, but you don't want it to receive "self" as the automatic first 
argument. That's pretty rare.

For a very long time, the only known use for staticmethod was in the 
tests checking that the staticmethod code worked correctly.

So that's what staticmethod does. It is occassionally useful, but not 
very often. Chances are, if you think you need one, you probably don't.

So why doesn't it work the way you expect? For that, read my next email.




-- 
Steven
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class functions/staticmethod?

2019-08-12 Thread Peter Otten
James Hartley wrote:

> I am lacking in understanding of the @staticmethod property.
> Explanation(s)/links might be helpful.  I have not found the descriptions
> found in the Internet wild to be particularly instructive.  Given the code
> below:
> =8<--
> from collections import namedtuple
> 
> class Foo():
> Dimensions = namedtuple('Dimensions', ['height', 'width'])
> _dimensions = Dimensions(3, 4)
> 
> def dimensions():
> print('id = {}'.format(id(Foo._dimensions)))
> return Foo._dimensions

That works with the class as Foo.dimensions is just a function in Python 3, 
but not with an instance because Python will try to pass the instance as the 
first argument

>>> Foo.dimensions()
id = 140192821560880
Dimensions(height=3, width=4)
>>> Foo().dimensions()
Traceback (most recent call last):
  File "", line 1, in 
TypeError: dimensions() takes 0 positional arguments but 1 was given

You can turn it into a static method

@staticmethod
def dimensions():
print('id = {}'.format(id(Foo._dimensions)))
return Foo._dimensions

>>> Foo.dimensions()
id = 139629779179056
Dimensions(height=3, width=4)
>>> Foo().dimensions()
id = 139629779179056
Dimensions(height=3, width=4)

or, when you are planning for subclases, into a classmethod:

$ cat staticmethod_demo.py
class Foo():
_dimensions = "foo-dimensions"

@classmethod
def class_dimensions(cls):
return cls._dimensions

@staticmethod
def static_dimensions():
return Foo._dimensions


class Bar(Foo):
_dimensions = "bar-dimensions"
$ python3 -i staticmethod_demo.py 
>>> Foo.class_dimensions(), Foo.static_dimensions()
('foo-dimensions', 'foo-dimensions')
>>> Bar.class_dimensions(), Bar.static_dimensions()
('bar-dimensions', 'foo-dimensions')

> 
> @staticmethod
> def dimensions1():
> print('id = {}'.format(id(_dimensions)))
> return _dimensions
> =8<--
> The class method Foo.dimensions() is capable of accessing class members,
> but Foo.dimensions1() cannot. What does the @staticmethod decorator really
> add?

You do not really need static methods; they work like module-level 
functions. They are more of a means to organize your code; by writing

class Foo:
   @staticmethod
   def bar(...): 
   do stuff

instead of

def foo_bar(...):
do stuff

class Foo:
pass

you make the mental association between the class and the function a bit 
stronger.

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


[Tutor] class functions/staticmethod?

2019-08-11 Thread James Hartley
I am lacking in understanding of the @staticmethod property.
Explanation(s)/links might be helpful.  I have not found the descriptions
found in the Internet wild to be particularly instructive.  Given the code
below:
=8<--
from collections import namedtuple

class Foo():
Dimensions = namedtuple('Dimensions', ['height', 'width'])
_dimensions = Dimensions(3, 4)

def dimensions():
print('id = {}'.format(id(Foo._dimensions)))
return Foo._dimensions

@staticmethod
def dimensions1():
print('id = {}'.format(id(_dimensions)))
return _dimensions
=8<--
The class method Foo.dimensions() is capable of accessing class members,
but Foo.dimensions1() cannot. What does the @staticmethod decorator really
add?

Thanks!
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class newbie

2017-07-23 Thread Michael C
thanks!

On Sun, Jul 23, 2017 at 5:35 PM, Danny Yoo  wrote:

> On Sun, Jul 23, 2017 at 1:24 PM, Michael C
>  wrote:
> > class mahschool:
> > def print():
> > print('Say something')
>
>
> By the way, you've chosen a name for your method that's spelled the
> same as the name of the built-in "print" function.  I'd recommend you
> choose a different name than "print" in your method name, just to
> avoid any potential confusion.  This isn't going to solve the
> immediate problem that you encountered and solved: you figured out
> that methods need to have a self argument.  But you probably still
> want to rename to avoid the name collision.
>
>
> Good luck!
>
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class newbie

2017-07-23 Thread Mats Wichmann
On 07/23/2017 02:42 PM, Michael C wrote:
> never mind, I forgot to put 'self' in the method definition!

class mahschool:
def print(self):
print('Say something')


a = mahschool()

a.print()

Indeed.  The error message was clear on this - but not in a way that's
always instructive until you're used to it :)

"TypeError: print() takes 0 positional arguments but 1 was given"

A method is called "silently" (you didn't pass it yourself as an
argument when you called print()) with the instance, so you need to
declare such a parameter in the method definition.

And to give myself an excuse for preaching: it's usually not a great
idea to reuse the name of a built-in function.
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class newbie

2017-07-23 Thread Danny Yoo
On Sun, Jul 23, 2017 at 1:24 PM, Michael C
 wrote:
> class mahschool:
> def print():
> print('Say something')


By the way, you've chosen a name for your method that's spelled the
same as the name of the built-in "print" function.  I'd recommend you
choose a different name than "print" in your method name, just to
avoid any potential confusion.  This isn't going to solve the
immediate problem that you encountered and solved: you figured out
that methods need to have a self argument.  But you probably still
want to rename to avoid the name collision.


Good luck!
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class newbie

2017-07-23 Thread Michael C
never mind, I forgot to put 'self' in the method definition!

class mahschool:
def print(self):
print('Say something')


a = mahschool()

a.print()


On Sun, Jul 23, 2017 at 1:24 PM, Michael C 
wrote:

> class mahschool:
> def print():
> print('Say something')
>
>
> a = mahschool()
>
> a.print()
>
>
>
> With this, I get this error:
>
> Traceback (most recent call last):
>   File "test.py", line 8, in 
> a.print()
> TypeError: print() takes 0 positional arguments but 1 was given
>
>
> What did I do wrong?
>
> Thanks!
>
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


[Tutor] class newbie

2017-07-23 Thread Michael C
class mahschool:
def print():
print('Say something')


a = mahschool()

a.print()



With this, I get this error:

Traceback (most recent call last):
  File "test.py", line 8, in 
a.print()
TypeError: print() takes 0 positional arguments but 1 was given


What did I do wrong?

Thanks!
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class

2017-06-21 Thread Alan Gauld via Tutor
On 20/06/17 23:39, Rex Florian via Tutor wrote:

> Can someone explain how Python achieves the vector addition of more than 2 
> vectors
> without some kind of looping?
> 
> class Vector:
>def __init__(self, a, b):
>def __str__():
>def __add__(self,other):
>   return Vector(self.a + other.a, self.b + other.b)

> print(v1 + v2 + v3)

When you do the addition Python evaluates it from left to right
so it is interpreted as:

((v1+v2) + v3)

so Python does:

v1.__add__(v2)

Which returns a new vector, let's call it vt

Python then does:

vt.__add__(v3)

which returns another new vector, lets call it result,
which is what gets printed using

print (result.__str__())


-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


[Tutor] Class

2017-06-21 Thread Rex Florian via Tutor

Hello,

Below is a class I am using to comprehend how class works.  
The code came from tutorialspoint.com and executes correctly but I do not 
understand why it works.
The original example defined just v1 and v2.  I decided to experiment and 
instantiated v3.
The executed the print statement yields a correct answer which baffles me as to 
how.
I also tried (v1 + v2 + v3 + v1) which works as well.

Can someone explain how Python achieves the vector addition of more than 2 
vectors
without some kind of looping?

class Vector:
   def __init__(self, a, b):
  self.a = a
  self.b = b

   def __str__(self):
  return 'Vector (%d, %d)' % (self.a, self.b)

   def __add__(self,other):
  return Vector(self.a + other.a, self.b + other.b)

v1 = Vector(2,10)
v2 = Vector(5,-2)
v3 = Vector(16,-14)
print(v1 + v2 + v3)
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class Inheritance

2017-02-21 Thread Peter Otten
Rafael Knuth wrote:

> Hey there,
> 
> I am trying to wrap my head around Class Inheritance in Python, and I
> wrote a little program which is supposed to calculate revenues from
> customers who don't get a discount (parent class) and those who get a
> 30% discount (child class):
> 
> class FullPriceCustomer(object):
> def __init__(self, customer, rate, hours):
> self.customer = customer
> self.rate = rate
> self.hours = hours
> 
> print ("Your customer %s made you %s USD this year." %
> (customer, rate * hours))
> 
> class DiscountCustomer(FullPriceCustomer):
> discount = 0.7
> def calculate_discount(self, rate, hours):
> print ("Your customer %s made you %s USD at a 30% discount
> rate this year." % (self.customer, self.rate * rate * discount))
> 
> customer_one = DiscountCustomer("Customer A", 75, 100)
> customer_two = FullPriceCustomer("Customer B", 75, 100)
> 
> The DiscountCustomer class instance gets me the wrong result (it does
> not calculate the discount) and I was not able to figure out what I
> did wrong here.
> Can anyone help? Thanks!

In a real application you would not introduce two classes for this -- a 
FullPriceCustomer would be a customer with a discount of 0%.

Then you mix output with initialisation, so let's fix that first:

class FullPriceCustomer(object):
def __init__(self, customer, rate, hours):
self.customer = customer
self.rate = rate
self.hours = hours

def print_summary(self):
print(
"Your customer %s made you %s USD this year." %
(self.customer, self.rate * self.hours)
)


customer = FullPriceCustomer("Customer B", 75, 100)
customer.print_summary()

Now look at your code: what has to change for a customer who gets a 
discount?

self.rate * self.hours

will become

self.discount * self.rate * self.hours

or as I prefer to store the part that the customer doesn't pay as the 
discount

(1 - self.discount) * self.rate * self.hours

To make overriding easy we put that calculation into a separate method:

class FullPriceCustomer(object):
def __init__(self, customer, rate, hours):
self.customer = customer
self.rate = rate
self.hours = hours

def print_summary(self):
print(
"Your customer %s made you %s USD this year." %
(self.customer, self.get_total())
)

def get_total(self):
return self.rate * self.hours


customer = FullPriceCustomer("Customer B", 75, 100)
customer.print_summary()

Then the DiscountCustomer class can be written

class FullPriceCustomer(object):
def __init__(self, customer, rate, hours):
self.customer = customer
self.rate = rate
self.hours = hours

def print_summary(self):
print(
"Your customer %s made you %s USD this year." %
(self.customer, self.get_total())
)

def get_total(self):
return self.rate * self.hours


class DiscountCustomer(FullPriceCustomer):
discount = 0.3
def get_total(self):
return (1 - self.discount) * self.rate * self.hours

customers = [
DiscountCustomer("Customer A", 75, 100),
FullPriceCustomer("Customer B", 75, 100),
]

for customer in customers:
customer.print_summary()

If we run that we see that the calculation may be correct, but the discount 
is not mentioned. We could solve this by overriding print_summary, but 
here's another way:

class FullPriceCustomer(object):
summary_template = (
"Your customer {0.customer} made you {0.total} USD this year."
)

def __init__(self, customer, rate, hours):
self.customer = customer
self.rate = rate
self.hours = hours

def print_summary(self):
print(self.summary_template.format(self))

@property
def total(self):
return self.rate * self.hours


class DiscountCustomer(FullPriceCustomer):
summary_template = (
"Your customer {0.customer} made you {0.total} USD "
"at a {0.discount:.0%} this year."
)
discount = 0.3

@property
def total(self):
return (1 - self.discount) * self.rate * self.hours


class VIC(DiscountCustomer):
discount = 0.33

customers = [
DiscountCustomer("Customer A", 75, 100),
FullPriceCustomer("Customer B", 75, 100),
VIC("Customer C", 75, 100),
]

for customer in customers:
customer.print_summary()

If one day you choose to use an isinstance check to see if you have a 
FullPriceCustomer

for customer in customers:
if isinstance(customer, FullPriceCustomer):
print(customer.customer, "pays the full price")

you may be surprised to see that all customers seem to be paying the full 
price. That's because isinstance(obj, class_) is true even if the actual 
class of obj is a subclass of class_. Therefore I recommend that you change 
your class hierarchy to

class Customer(object):
   ...

class FullPriceCustomer(Customer):
   ...

Re: [Tutor] Class Inheritance

2017-02-21 Thread Alan Gauld via Tutor
On 21/02/17 09:49, Rafael Knuth wrote:

> class DiscountCustomer(FullPriceCustomer):
> discount = 0.7
> def calculate_discount(self, rate, hours):
> print ("Your customer %s made you %s USD at a 30% discount
> rate this year." % (self.customer, self.rate * rate * discount))

I meant to add... are you sure that calculation is what you meant?
First point is that discount is not defined, you need to prefix
it with either self or DiscountCustomer.
But also, it doesn't use hours? Is that correct?

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class Inheritance

2017-02-21 Thread Alan Gauld via Tutor
On 21/02/17 09:49, Rafael Knuth wrote:

> class FullPriceCustomer(object):
> def __init__(self, customer, rate, hours):
> 
> 
> class DiscountCustomer(FullPriceCustomer):
> discount = 0.7
> def calculate_discount(self, rate, hours):
> 
> customer_one = DiscountCustomer("Customer A", 75, 100)
> customer_two = FullPriceCustomer("Customer B", 75, 100)

You create two instances and as such the
FullPriceCustomer.__init__() method gets
executed in both cases. This is because
the subclass does not provide an __init__()
of its own, so the inherited one is used.

Your discount is calculated in the
calculate_discount() method, but that is
never called. If you added a line:

customer_one.calculate_discount(75,100)

you would see the discount appear.

Alternatively create an init() for your
subclass that calls the superclass init()
then calls

self.calculate_discount(rate,hours)

BTW It's bad practice to mix calculations
and display(print) in the same method,
it's better to separate them, but
that's probably a topic for another thread
Get the inheritance sorted first :-)

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


[Tutor] Class Inheritance

2017-02-21 Thread Rafael Knuth
Hey there,

I am trying to wrap my head around Class Inheritance in Python, and I
wrote a little program which is supposed to calculate revenues from
customers who don't get a discount (parent class) and those who get a
30% discount (child class):

class FullPriceCustomer(object):
def __init__(self, customer, rate, hours):
self.customer = customer
self.rate = rate
self.hours = hours

print ("Your customer %s made you %s USD this year." %
(customer, rate * hours))

class DiscountCustomer(FullPriceCustomer):
discount = 0.7
def calculate_discount(self, rate, hours):
print ("Your customer %s made you %s USD at a 30% discount
rate this year." % (self.customer, self.rate * rate * discount))

customer_one = DiscountCustomer("Customer A", 75, 100)
customer_two = FullPriceCustomer("Customer B", 75, 100)

The DiscountCustomer class instance gets me the wrong result (it does
not calculate the discount) and I was not able to figure out what I
did wrong here.
Can anyone help? Thanks!

All the best,

Rafael
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class learning

2015-01-23 Thread Alan Gauld

On 23/01/15 01:44, jarod...@libero.it wrote:


How can gave the attributes __name__ to a function?


You don't Python does it for you.



class Foo(object):

 def __init__(self):
 steps = {}
 tmp = open("rnaseq.base.ini","rb")
 config.readfp(tmp)
 readsets = 
parse_illumina_readset_file("/home/mauro/Desktop/readset.csv")


You realise that steps is a local variable that is not used and gets 
thrown away. So its a waste of space.

Similarly you read the config file but throw away the results.
Again a waste of space.
And the same with readsets.
Your init does a lot of work to no long term effect.


 @property
 def steps(self):
 return [

 self.one,
 self.two,
 self.fmit,
 ]
 def one(self):
 a = 5
 return a

...

 #@property
 def show(self):
 ftp="\n".join([str(idx + 1) + "- " + step.__name__  for idx, step in 
enumerate(self.steps)])

 print ftp
It is working

In [5]: F =  Foo()

In [6]: F.show()
1- one
2- two
3- fmit


Yes, as expected.


Why if I define the data in the same way  I have this error?

 in ()
> 1 rna.show()

 in show(self)
 261 #@property
 262 def show(self):
--> 263 ftp="\n".join([str(idx + 1) + "- " + step.__name__  for 
idx, step in enumerate(self.steps)])
 264
 265 print ftp

AttributeError: 'str' object has no attribute '__name__'


Because you didn't define it in the same way.

Consider this example from the pastebin:

   @property
def star(self):
print "Mitico Star"
return "name"


Here you make star a property so when in steps you store self.star you 
are not storing a reference to the method, as you did above, you are 
storing the return value of star - "name".


Now in show() you try to take the __name__ of "name" but, as the error 
says, strings don't have __name__ attributes.


The same applies to some, but not all, of the other method names in steps...

You would make life much easier if you got rid of all the property stuff 
(some of it commented out and others not). Just use the

methods and data attributes directly, it makes life so much easier.



Here you find all the other code the principal are the 
same:http://pastebin.com/nYGEiXY4



HTH
--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class learning

2015-01-23 Thread Danny Yoo
You are trying to use advanced features of Python, and they are not
the right tool for what you're trying to do.

Specifically, you're trying two things at the same time:

1.  Properties, which allows method calls to look like simple variable access.

2.  The __name__ special attribute on methods (reference:
https://docs.python.org/2/reference/datamodel.html) to reflectively
pick up a string that lets us get the name of a function.


The problem is trying to use *both* of these features at the same
time.  It is self defeating.


Here is a minimal example to demonstrate;

##
class Test(object):
@property
def x(self):
return 42
##

Consider the expression:

Test2().x.__name__

This example is small enough that it should help to clarify what's
going on.  What did you want to happen?  And what happens?



Now look at:

#
class Test(object):
def x(self):
return 42

Test().x().__name__
#

What do you expect to see when you run this, and why?


The technical error in the first case is the same as the second.


In short, I would strongly suggest you don't use @property, especially
if you're learning the language.  It's an advanced feature.  In your
particular case, you're getting into unnecessary trouble by using it.
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class learning

2015-01-23 Thread Danny Yoo
On Fri, Jan 23, 2015 at 12:37 AM, jarod...@libero.it  wrote:
> Thanks for the help and patience!
> It is a function on the class so I suppose for read that function  list I
> need self.steps Where I'm wrong?
> @property
> def steps(self):
> return [
>
> self.trimmomatic,
> self.merge_trimmomatic_stats,
> self.star,
> self.picard_sort_sam,
> self.rnaseqc,
> self.wiggle,
> self.cufflinks,
> self.gq_seq_utils_exploratory_analysis_rnaseq
>
> ]
>



Do each of these elements in this list support the operations you're
performing on any single step?

That is, the code that you have here:

def show(self):
ftp="\n".join([str(idx + 1) + "- " + step.__name__  for idx,
step in enumerate(self.steps)])

seems to assume that every step must have a '__name__' property.

But do all of the steps that you've put in there support '__name__'?
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class learning

2015-01-23 Thread Danny Yoo
> #@property
> def show(self):
> ftp="\n".join([str(idx + 1) + "- " + step.__name__  for idx, step
in enumerate(self.steps)])
>

Questions you should be asking yourself:

What is self.steps?  What type is it?

In the case where this breaks with an error, what is self.steps then?
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class errors

2015-01-23 Thread Patrick Thunstrom
If the code I'm seeing is correct, the problem is the class is Jobs,
and you instantiated a Job, which doesn't exit.

Replace one with the other in either case should fix it.

On Thu, Jan 22, 2015 at 11:11 AM, jarod...@libero.it  wrote:
> Dear All,
>
> I created a class that invoke  from another file another class
>  I get an error that I do not understand: gobal name Job is not defined
> However If I see the class imported I found the class Job.
> Any suggestion or example on class invoke another class
>
> #job,py
> class Jobs:
> .
>
> #trial.py
>
> from core.job import *
> class Second:
> def __initi__:
> tp = open("/tmp/file.txt")
>
> def gus(self):
> tr = Job()
>
> thanks so much!1
>
> ___
> Tutor maillist  -  Tutor@python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


[Tutor] Class learning

2015-01-22 Thread jarod...@libero.it
Dear All
How can gave the attributes __name__ to a function? 
class Foo(object):

 
def __init__(self):
steps = {}
tmp = open("rnaseq.base.ini","rb")
config.readfp(tmp)
readsets = 
parse_illumina_readset_file("/home/mauro/Desktop/readset.csv")


@property
def steps(self):
return [

self.one,
self.two,
self.fmit,


]
def one(self):
a = 5
return a
def two(self):
b = 5
return b

def fmit(self):
c = 7
return c

#@property
def show(self):
ftp="\n".join([str(idx + 1) + "- " + step.__name__  for idx, step in 
enumerate(self.steps)])

print ftp
It is working

In [5]: F =  Foo()

In [6]: F.show()
1- one
2- two
3- fmit

Why if I define the data in the same way  I have this error?

 in ()
> 1 rna.show()

 in show(self)
261 #@property
262 def show(self):
--> 263 ftp="\n".join([str(idx + 1) + "- " + step.__name__  for 
idx, step in enumerate(self.steps)])
264 
265 print ftp

AttributeError: 'str' object has no attribute '__name__'
Here you find all the other code the principal are the 
same:http://pastebin.com/nYGEiXY4
rna = Rnaseq()
rna.show()
thanks so much!!

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class errors

2015-01-22 Thread Cameron Simpson

On 22Jan2015 17:11, jarod...@libero.it  wrote:

I created a class that invoke  from another file another class
I get an error that I do not understand: gobal name Job is not defined
However If I see the class imported I found the class Job.
Any suggestion or example on class invoke another class


First, please cut/paste error messages, filenames and code. Do not hand type 
them, as that introduces errors.



#job,py


For example, I suspect you mean "job.py", not "job,py".


class Jobs:
   .

#trial.py

from core.job import *


It is not recommended to import "*". Just impor the names you need. It avoids 
_unexpected_ names leaking into your program: you might be using such a name 
for something else!



class Second:
   def __initi__:
   tp = open("/tmp/file.txt")

   def gus(self):
   tr = Job()


Because you have hand typed things I cannot be sure - it may just be a mistake 
- but "job.py" defines a class "Jobs". In "trial.py" you use the name "Job".

Not the same!

Cheers,
Cameron Simpson 

Beware of bugs in the above code; I have only proved it correct, not tried it.
- Donald E. Knuth
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class errors

2015-01-22 Thread Danny Yoo
On Thu, Jan 22, 2015 at 8:11 AM, jarod...@libero.it  wrote:
> Dear All,
>
> I created a class that invoke  from another file another class
>  I get an error that I do not understand: gobal name Job is not defined

Please use copy-and-paste.  You just typed out the error message by
hand: we can tell because the error message you're presenting is
misspelled.  Copy-and-paste it, as well as the surrounding text around
it.


> However If I see the class imported I found the class Job.

Ok.  But where?  In the code you present:


> #job,py
> class Jobs:
> .
>
> #trial.py
>
> from core.job import *
> class Second:
> def __initi__:
> tp = open("/tmp/file.txt")
>
> def gus(self):
> tr = Job()


I don't see a class named 'Job'.  I see a class named 'Jobs' defined
in 'job.py', but that's a different class.
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


[Tutor] Class errors

2015-01-22 Thread jarod...@libero.it
Dear All,

I created a class that invoke  from another file another class
 I get an error that I do not understand: gobal name Job is not defined
However If I see the class imported I found the class Job.
Any suggestion or example on class invoke another class

#job,py
class Jobs:
.

#trial.py

from core.job import *
class Second:
def __initi__:
tp = open("/tmp/file.txt")

def gus(self):
tr = Job()

thanks so much!1

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class to function

2014-05-25 Thread Danny Yoo
> i am trying to understand this code:
> http://nbviewer.ipython.org/gist/BenLangmead/6665861

I'm slightly familiar with the purpose of the code.  It's constructing
a Suffix Tree, though not in linear time.

Reading the code... ah.  I see.  This is enumerating through all
suffixes, and building it by repeated insertion into a trie.

http://en.wikipedia.org/wiki/Trie

The classes are used here to represent structured data and operations
to be performed on that structured data.  The code fundamentally has a
structured value called a Node, with two fields to represent the
string label and the links to other nodes.



Aside: there is a very good book by Dan Gusfield that talks about
suffix trees and how to construct them called "Algorithms on Strings,
Trees and Sequences: Computer Science and Computational Biology"


http://www.amazon.com/Algorithms-Strings-Trees-Sequences-Computational/dp/0521585198

which you may want to look at if you're interested in these algorithms.


It is probably not a good idea to try to intermix trying to understand
an algorithm like this at the same time as you're learning basic
features in your programming language.  Consider a slightly simpler
example to learn about "classes", apart from the algorithms you are
studying.  Most good Python tutorials should cover how to use classes
to build structured data and manipulate it.  Alan Gauld's Python
tutorial, for example, should have a section on this.

http://www.alan-g.me.uk/tutor/tutclass.htm
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class to function

2014-05-25 Thread Alan Gauld

On 25/05/14 16:39, rahmad akbar wrote:

Hi guys

i am trying to understand this code:
http://nbviewer.ipython.org/gist/BenLangmead/6665861

i understand functions quite alright . but i have no idea about
classes yet.


Do you understand modules?
Modules contain functions and data that you can reuse
across programs. Are you comfortable with the idea of
importing and using modules?

Classes are one step on from modules.
A module can contain data but that data is restricted in
that you can only have a single instance of it. For example
if you had a module full of functions for processing a data
tree and the root was a module variable. You can load the
tree and use it just fine. But if you want to work with
more than one tree you either have to throw away (or cache)
the old tree before populating the new one or combine
both trees under a single root (which probably won't work well).

To solve that you build the module functions and data into
a Tree class. Then you can create multiple Trees each
with their own root. To do that you take each of the module
functions and put then into the class as "methods". You then
put the global root variable  into the class as instance
data. You do that by creating an __init__() method that
accepts the root data as a parameter and populates
the instance root variable (self.root).

When you create an instance of a tree you pass in the root
variable and Python "magically" calls the __init__()
method, passing your root in to it.

You probably have been doing this with things like strings
for ages. You create a string by assigning a string literal

s = 'my string'

instead of explicitly calling

s = str('my string')

But the effect is the same. You create an instance of a
string object which has methods attached, like upper(),
split() etc,

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.flickr.com/photos/alangauldphotos

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class to function

2014-05-25 Thread Alex Kleider

On 2014-05-25 09:20, R. Alan Monroe wrote:

can you
guys help explain. super thanks


A class is like a blueprint.
An instance of that class is like a house built from that blueprint.

Think about it. An infinite number of houses could be constructed
using those blueprints. But the architect only had to draw them once.

__init__() is like the "foundation" of each house that is built. In
otherwords, the stuff you do first when construction commences.

Alan


I very much like this analogy but might I suggest a slight modification?
 __init__() builds the house, and possibly provides minimum 
furnishings[1] (with parameters passed to init;)  then your code 
(usually using the associated methods) flushes out the furnishings[1] 
(and makes use of them) as the needs of your program demand.

[1] 'furnishings' in this analogy are DATA
Does this fit?  Comments welcome.
Respectively submitted,
ak
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class to function

2014-05-25 Thread R. Alan Monroe
> can you
> guys help explain. super thanks

A class is like a blueprint.
An instance of that class is like a house built from that blueprint.

Think about it. An infinite number of houses could be constructed
using those blueprints. But the architect only had to draw them once.

__init__() is like the "foundation" of each house that is built. In
otherwords, the stuff you do first when construction commences.

Alan

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


[Tutor] class to function

2014-05-25 Thread rahmad akbar
Hi guys

i am trying to understand this code:
http://nbviewer.ipython.org/gist/BenLangmead/6665861

i understand functions quite alright . but i have no idea about
classes yet. the code is written using class and i could not make much
sense out of it. all this init and self thingy drive me crazy. can you
guys help explain. super thanks

-- 
many thanks
mat
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class decorator on a derived class not initialising the base classes using super - TypeError

2014-02-24 Thread Sangeeth Saravanaraj
Peter, Spir - thanks for your time and effort!

I am posting this query to few more Python mailers.

Thank you,

Sangeeth


On Tue, Feb 25, 2014 at 5:22 AM, spir  wrote:

> On 02/24/2014 08:19 PM, Sangeeth Saravanaraj wrote:
>
>> Sorry, I should have described what I was trying!
>>
>> I want to create a decorator which should do the following things:
>>
>> - When an object of the decorated class is created, the objects name
>>
>> (say the value of the incoming "id" argument) should be stored as a
>> record
>> in a table in a database.
>> - When an object of the decorated class is deleted, the record with
>> this
>>
>> deleted objects name (i.e. object.id) should be removed from the
>> table.
>>
>> You can safely assume that all the database operations are working fine!
>>
>> Now, for example - consider the following snippet:
>>
>> @saveme
>> class A(object):
>>  def __init__(self, id):
>>  self.id = id
>>
>> @saveme
>> class B(object):
>>  def __init__(self, id):
>>  self.id = id
>>
>> "saveme" should do what I have explained earlier.
>>
>> a1 = A("A1")
>> a2 = A("A2")
>> a3 = A("A3")
>> b1 = B("B1")
>> b2 = B("B2")
>>
>> At this point if I query and print all the records in a table, I should
>> get
>> the following:
>> output: ["A1", "A2", "A3", "B1", "B2"]
>>
>> del a1
>> del a2
>> del a3
>> del b1
>> del b2
>>
>> At this point, all entries in the table should be deleted; query should
>> return an empty list!
>>
>> And, I want to highlight that the classes that are being decorated with
>> "saveme" can de derived classes too!
>>
>> What is the best way to do this?!
>>
>> Thank you,
>>
>> Sangeeth
>>
>
> Your problem looks like a typical "crosscutting" (transversal) concern
> addressed by AOP (Aspect Oriented Programming). Their usual example is in
> fact logging. Look at the wikipedia page:
> https://en.wikipedia.org/wiki/Aspect-oriented_programming
>
> Not that it would help you solve it _in python_, but this may serve at
> least to better understand what kind of problem you are actually facing;
> and why it is annoying in programming (with common languages); what may be
> your options.
>
> [I have no better approach than yours, using magic metamethods, and a
> decorator to wrap it all.]
>
>
> d
> ___
> Tutor maillist  -  Tutor@python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class decorator on a derived class not initialising the base classes using super - TypeError

2014-02-24 Thread spir

On 02/24/2014 08:19 PM, Sangeeth Saravanaraj wrote:

Sorry, I should have described what I was trying!

I want to create a decorator which should do the following things:

- When an object of the decorated class is created, the objects name
(say the value of the incoming "id" argument) should be stored as a record
in a table in a database.
- When an object of the decorated class is deleted, the record with this
deleted objects name (i.e. object.id) should be removed from the table.

You can safely assume that all the database operations are working fine!

Now, for example - consider the following snippet:

@saveme
class A(object):
 def __init__(self, id):
 self.id = id

@saveme
class B(object):
 def __init__(self, id):
 self.id = id

"saveme" should do what I have explained earlier.

a1 = A("A1")
a2 = A("A2")
a3 = A("A3")
b1 = B("B1")
b2 = B("B2")

At this point if I query and print all the records in a table, I should get
the following:
output: ["A1", "A2", "A3", "B1", "B2"]

del a1
del a2
del a3
del b1
del b2

At this point, all entries in the table should be deleted; query should
return an empty list!

And, I want to highlight that the classes that are being decorated with
"saveme" can de derived classes too!

What is the best way to do this?!

Thank you,

Sangeeth


Your problem looks like a typical "crosscutting" (transversal) concern addressed 
by AOP (Aspect Oriented Programming). Their usual example is in fact logging. 
Look at the wikipedia page:

https://en.wikipedia.org/wiki/Aspect-oriented_programming

Not that it would help you solve it _in python_, but this may serve at least to 
better understand what kind of problem you are actually facing; and why it is 
annoying in programming (with common languages); what may be your options.


[I have no better approach than yours, using magic metamethods, and a decorator 
to wrap it all.]


d
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class decorator on a derived class not initialising the base classes using super - TypeError

2014-02-24 Thread Peter Otten
Sangeeth Saravanaraj wrote:

> On Mon, Feb 24, 2014 at 10:53 PM, Peter Otten <__pete...@web.de> wrote:
> 
>> Sangeeth Saravanaraj wrote:
>>
>> > I am trying to capture an object initiation and deletion events using
>> > the __call__() and __del__() methods with the following approach.
>>
>> Note that there is no guarantee that __dell__ will ever be called.
>> Usually it is better to introduce a weakref with callback.
>>
>> > class A(object):
>> > def __init__(self, klass):
>> > print "A::__init__()"
>> > self._klass = klass
>> >
>> > def __call__(self):
>> > print "A::__call__()"
>> > return self._klass()
>> >
>> > def __del__(self):
>> > print "A::__del__()"
>> >
>> > class Parent1(object):
>> > def __init__(self):
>> > print "Parent1:: __init__()"
>> > super(Parent1, self).__init__()
>> >
>> > class Parent2(object):
>> > def __init__(self):
>> > print "Parent2:: __init__()"
>> > super(Parent2, self).__init__()
>> >
>> > @A
>> > class B(Parent1, Parent2):
>> > def __init__(self):
>> > print "B::__init__()"
>> > super(B, self).__init__()
>> >
>> > def main():
>> > b = B()
>> >
>> > if __name__ == "__main__":
>> > main()
>> >
>> >
>> > I decorate a class, say class B (whose object initiation and deletion I
>> > wanted to capture) with a decorator class A. Please note that the class
>> > B is derived from two classes - Parent1 & Parent2 and I want to use
>> > super() method to initialise the parent classes.
>> >
>> > When I executed the above code snippet, I ran into the following issue:
>> >
>> >
>> > A::__init__()
>> > A::__call__()
>> > B::__init__()
>> > Traceback (most recent call last):
>> >   File "so.py", line 40, in 
>> > main()
>> >   File "so.py", line 36, in main
>> > b = B()
>> >   File "so.py", line 10, in __call__
>> > return self._klass()
>> >   File "so.py", line 32, in __init__
>> > super(B, self).__init__()
>> > TypeError: must be type, not A
>> > A::__del__()
>> >
>> >
>> > When I commented "super(B, self).__init__()" in the class B ::
>> > __init__() method, it returned an object of type B and I was able to
>> > see the prints in the __call__ and __del__ methods but the __init__()
>> > methods of the
>> base
>> > classes (Parent1 & Parent2) are not called!
>> >
>> > From the error message, what I could understand is - the object
>> > returned by A::__call__() is not of type B but of type A. But when I
>> > put a print
>> in
>> > the A::__call__() I could see it returns an object of type B and not A.
>> >
>> > Now the question is - With this approach to capture the initiation and
>> > deletion events of an object, how do I initialise the base classes
>> > using super()?
>>
>> You'd have to introduce a naming convention or rewrite your class to be
>> aware of the wrapping in some way:
>>
>> @A
>> class B(Parent1, Parent2):
>> def __init__(self):
>> print "B::__init__()"
>> super(B._klass, self).__init__()
>>
>> Not pretty.
>>
>> > Or, is there any other better way to capture the __call__ and __del__
>> >  events for an object of a certain class - if so, how?!
>>
>> Most certainly, but you have to give some details about what you are up
>> to first.
>>
> 
> Sorry, I should have described what I was trying!
> 
> I want to create a decorator which should do the following things:
> 
>- When an object of the decorated class is created, the objects name
>(say the value of the incoming "id" argument) should be stored as a
>record in a table in a database.
>- When an object of the decorated class is deleted, the record with
>this deleted objects name (i.e. object.id) should be removed from the
>table.
> 
> You can safely assume that all the database operations are working fine!
> 
> Now, for example - consider the following snippet:
> 
> @saveme
> class A(object):
> def __init__(self, id):
> self.id = id
> 
> @saveme
> class B(object):
> def __init__(self, id):
> self.id = id
> 
> "saveme" should do what I have explained earlier.
> 
> a1 = A("A1")
> a2 = A("A2")
> a3 = A("A3")
> b1 = B("B1")
> b2 = B("B2")
> 
> At this point if I query and print all the records in a table, I should
> get the following:
> output: ["A1", "A2", "A3", "B1", "B2"]
> 
> del a1
> del a2
> del a3
> del b1
> del b2
> 
> At this point, all entries in the table should be deleted; query should
> return an empty list!
> 
> And, I want to highlight that the classes that are being decorated with
> "saveme" can de derived classes too!
> 
> What is the best way to do this?!

I'm sorry, after a bit of try-and-error I could not come up with a good way 
to write such a decorator. My best effort so far uses inheritance:

import itertools
import weakref

_registry = weakref.WeakValueDictionary()
_next_id = lambda count=itertools.count(): next(count)

def show():
print(list(_registry.values()))

class Registered(object):
def __i

Re: [Tutor] Class decorator on a derived class not initialising the base classes using super - TypeError

2014-02-24 Thread Sangeeth Saravanaraj
On Mon, Feb 24, 2014 at 10:53 PM, Peter Otten <__pete...@web.de> wrote:

> Sangeeth Saravanaraj wrote:
>
> > I am trying to capture an object initiation and deletion events using the
> > __call__() and __del__() methods with the following approach.
>
> Note that there is no guarantee that __dell__ will ever be called. Usually
> it is better to introduce a weakref with callback.
>
> > class A(object):
> > def __init__(self, klass):
> > print "A::__init__()"
> > self._klass = klass
> >
> > def __call__(self):
> > print "A::__call__()"
> > return self._klass()
> >
> > def __del__(self):
> > print "A::__del__()"
> >
> > class Parent1(object):
> > def __init__(self):
> > print "Parent1:: __init__()"
> > super(Parent1, self).__init__()
> >
> > class Parent2(object):
> > def __init__(self):
> > print "Parent2:: __init__()"
> > super(Parent2, self).__init__()
> >
> > @A
> > class B(Parent1, Parent2):
> > def __init__(self):
> > print "B::__init__()"
> > super(B, self).__init__()
> >
> > def main():
> > b = B()
> >
> > if __name__ == "__main__":
> > main()
> >
> >
> > I decorate a class, say class B (whose object initiation and deletion I
> > wanted to capture) with a decorator class A. Please note that the class B
> > is derived from two classes - Parent1 & Parent2 and I want to use super()
> > method to initialise the parent classes.
> >
> > When I executed the above code snippet, I ran into the following issue:
> >
> >
> > A::__init__()
> > A::__call__()
> > B::__init__()
> > Traceback (most recent call last):
> >   File "so.py", line 40, in 
> > main()
> >   File "so.py", line 36, in main
> > b = B()
> >   File "so.py", line 10, in __call__
> > return self._klass()
> >   File "so.py", line 32, in __init__
> > super(B, self).__init__()
> > TypeError: must be type, not A
> > A::__del__()
> >
> >
> > When I commented "super(B, self).__init__()" in the class B :: __init__()
> > method, it returned an object of type B and I was able to see the prints
> > in the __call__ and __del__ methods but the __init__() methods of the
> base
> > classes (Parent1 & Parent2) are not called!
> >
> > From the error message, what I could understand is - the object returned
> > by A::__call__() is not of type B but of type A. But when I put a print
> in
> > the A::__call__() I could see it returns an object of type B and not A.
> >
> > Now the question is - With this approach to capture the initiation and
> > deletion events of an object, how do I initialise the base classes using
> > super()?
>
> You'd have to introduce a naming convention or rewrite your class to be
> aware of the wrapping in some way:
>
> @A
> class B(Parent1, Parent2):
> def __init__(self):
> print "B::__init__()"
> super(B._klass, self).__init__()
>
> Not pretty.
>
> > Or, is there any other better way to capture the __call__ and __del__
> >  events for an object of a certain class - if so, how?!
>
> Most certainly, but you have to give some details about what you are up to
> first.
>

Sorry, I should have described what I was trying!

I want to create a decorator which should do the following things:

   - When an object of the decorated class is created, the objects name
   (say the value of the incoming "id" argument) should be stored as a record
   in a table in a database.
   - When an object of the decorated class is deleted, the record with this
   deleted objects name (i.e. object.id) should be removed from the table.

You can safely assume that all the database operations are working fine!

Now, for example - consider the following snippet:

@saveme
class A(object):
def __init__(self, id):
self.id = id

@saveme
class B(object):
def __init__(self, id):
self.id = id

"saveme" should do what I have explained earlier.

a1 = A("A1")
a2 = A("A2")
a3 = A("A3")
b1 = B("B1")
b2 = B("B2")

At this point if I query and print all the records in a table, I should get
the following:
output: ["A1", "A2", "A3", "B1", "B2"]

del a1
del a2
del a3
del b1
del b2

At this point, all entries in the table should be deleted; query should
return an empty list!

And, I want to highlight that the classes that are being decorated with
"saveme" can de derived classes too!

What is the best way to do this?!

Thank you,

Sangeeth



>
> > PS:
> > http://stackoverflow.com/questions/21826854/typeerror-when-using-super-
> method-with-class-decorator-for-a-derived-class
>
>
> ___
> Tutor maillist  -  Tutor@python.org
> To unsubscribe or change subscription options:
> https://mail.python.org/mailman/listinfo/tutor
>
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class decorator on a derived class not initialising the base classes using super - TypeError

2014-02-24 Thread Peter Otten
Sangeeth Saravanaraj wrote:

> I am trying to capture an object initiation and deletion events using the
> __call__() and __del__() methods with the following approach.

Note that there is no guarantee that __dell__ will ever be called. Usually 
it is better to introduce a weakref with callback.

> class A(object):
> def __init__(self, klass):
> print "A::__init__()"
> self._klass = klass
> 
> def __call__(self):
> print "A::__call__()"
> return self._klass()
> 
> def __del__(self):
> print "A::__del__()"
> 
> class Parent1(object):
> def __init__(self):
> print "Parent1:: __init__()"
> super(Parent1, self).__init__()
> 
> class Parent2(object):
> def __init__(self):
> print "Parent2:: __init__()"
> super(Parent2, self).__init__()
> 
> @A
> class B(Parent1, Parent2):
> def __init__(self):
> print "B::__init__()"
> super(B, self).__init__()
> 
> def main():
> b = B()
> 
> if __name__ == "__main__":
> main()
> 
> 
> I decorate a class, say class B (whose object initiation and deletion I
> wanted to capture) with a decorator class A. Please note that the class B
> is derived from two classes - Parent1 & Parent2 and I want to use super()
> method to initialise the parent classes.
> 
> When I executed the above code snippet, I ran into the following issue:
> 
> 
> A::__init__()
> A::__call__()
> B::__init__()
> Traceback (most recent call last):
>   File "so.py", line 40, in 
> main()
>   File "so.py", line 36, in main
> b = B()
>   File "so.py", line 10, in __call__
> return self._klass()
>   File "so.py", line 32, in __init__
> super(B, self).__init__()
> TypeError: must be type, not A
> A::__del__()
> 
> 
> When I commented "super(B, self).__init__()" in the class B :: __init__()
> method, it returned an object of type B and I was able to see the prints
> in the __call__ and __del__ methods but the __init__() methods of the base
> classes (Parent1 & Parent2) are not called!
> 
> From the error message, what I could understand is - the object returned
> by A::__call__() is not of type B but of type A. But when I put a print in
> the A::__call__() I could see it returns an object of type B and not A.
> 
> Now the question is - With this approach to capture the initiation and
> deletion events of an object, how do I initialise the base classes using
> super()?

You'd have to introduce a naming convention or rewrite your class to be 
aware of the wrapping in some way:

@A
class B(Parent1, Parent2):
def __init__(self):
print "B::__init__()"
super(B._klass, self).__init__()

Not pretty. 

> Or, is there any other better way to capture the __call__ and __del__
>  events for an object of a certain class - if so, how?!

Most certainly, but you have to give some details about what you are up to 
first.

> PS:
> http://stackoverflow.com/questions/21826854/typeerror-when-using-super-
method-with-class-decorator-for-a-derived-class


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


[Tutor] Class decorator on a derived class not initialising the base classes using super - TypeError

2014-02-24 Thread Sangeeth Saravanaraj
I am trying to capture an object initiation and deletion events using the
__call__() and __del__() methods with the following approach.


class A(object):
def __init__(self, klass):
print "A::__init__()"
self._klass = klass

def __call__(self):
print "A::__call__()"
return self._klass()

def __del__(self):
print "A::__del__()"

class Parent1(object):
def __init__(self):
print "Parent1:: __init__()"
super(Parent1, self).__init__()

class Parent2(object):
def __init__(self):
print "Parent2:: __init__()"
super(Parent2, self).__init__()

@A
class B(Parent1, Parent2):
def __init__(self):
print "B::__init__()"
super(B, self).__init__()

def main():
b = B()

if __name__ == "__main__":
main()


I decorate a class, say class B (whose object initiation and deletion I
wanted to capture) with a decorator class A. Please note that the class B
is derived from two classes - Parent1 & Parent2 and I want to use super()
method to initialise the parent classes.

When I executed the above code snippet, I ran into the following issue:


A::__init__()
A::__call__()
B::__init__()
Traceback (most recent call last):
  File "so.py", line 40, in 
main()
  File "so.py", line 36, in main
b = B()
  File "so.py", line 10, in __call__
return self._klass()
  File "so.py", line 32, in __init__
super(B, self).__init__()
TypeError: must be type, not A
A::__del__()


When I commented "super(B, self).__init__()" in the class B :: __init__()
method, it returned an object of type B and I was able to see the prints in
the __call__ and __del__ methods but the __init__() methods of the base
classes (Parent1 & Parent2) are not called!

>From the error message, what I could understand is - the object returned by
A::__call__() is not of type B but of type A. But when I put a print in the
A::__call__() I could see it returns an object of type B and not A.

Now the question is - With this approach to capture the initiation and
deletion events of an object, how do I initialise the base classes using
super()?

Or, is there any other better way to capture the __call__ and __del__
 events for an object of a certain class - if so, how?!

Thank you,

Sangeeth


PS:
http://stackoverflow.com/questions/21826854/typeerror-when-using-super-method-with-class-decorator-for-a-derived-class
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class variables

2013-12-21 Thread eryksun
On Sat, Dec 21, 2013 at 12:40 PM, Steven D'Aprano  wrote:
> On Sat, Dec 21, 2013 at 08:41:17AM -0500, eryksun wrote:
>>
>> >>> vars(type)['__base__']
>> 
>
> Oooh, nice! I always forget about vars(), and end up messing about with
> __dict__.

It's a bit more efficient to use the __dict__ attribute, but I like
built-in vars().

vars(obj) is basically doing the equivalent of getattr(obj,
'__dict__'), so there's that plus the overhead of the call. vars has
to play it safe. A class may define a custom __dict__ property, such
as the tuple subclass created by namedtuple:

from collections import namedtuple

Point = namedtuple('Point', 'x y')
p = Point(1, 2)

>>> type(vars(Point)['__dict__'])


>>> vars(p)
OrderedDict([('x', 1), ('y', 2)])

Even if an object has a dict, it would be wrong for vars to naively
return a reference. A class might be overriding __getattribute__ to
create dynamic attributes or raise an AttributeError for '__dict__'.
Also, bypassing the descriptor would bypass the proxy protecting a
class dict, enabling silliness:

from ctypes import pythonapi, py_object

# 3.3+
pythonapi.PyObject_GenericGetDict.restype = py_object
pythonapi.PyObject_GenericGetDict.argtypes = [py_object]

str_dict = pythonapi.PyObject_GenericGetDict(str)
str_dict['lower'] = str_dict['upper']

>>> 'abc'.lower()
'ABC'
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class variables

2013-12-21 Thread Steven D'Aprano
On Sat, Dec 21, 2013 at 08:41:17AM -0500, eryksun wrote:
> On Sat, Dec 21, 2013 at 2:14 AM, Steven D'Aprano  wrote:
> >
> > (Sometimes, people will call them "members", especially if they are used
> > to C#. The meaning here is member as in an arm or leg, as in
> > "dismember", not member in the sense of belonging to a group.)
> 
> A Python object isn't just a fixed-size block of data with members at
> fixed offsets. It stores its data dynamically in a dict.

Yes, but that's just an implementation detail. There's no fundamental 
difference between "attribute", "member" and "(instance/class) 
variable". Different languages give them different names according to 
whatever vagaries the language creator considers important. C# happens 
to use fixed-sized records, Python happens to (usually) use dicts.

Having said that, I do think it is useful to reserve the term "member" 
for the fixed-size block type, and "attribute" for the general term. At 
least when talking about Python.

[...]
> For example, the read-only __base__ attribute of a class uses the
> following descriptor:
> 
> >>> vars(type)['__base__']
> 

Oooh, nice! I always forget about vars(), and end up messing about with 
__dict__.


> > Suppose we ask Python for "polly.colour". Python looks at the instance
> > polly, and checks to see if it has an instance attribute called "polly".
[...]

> It first has to check Parrot and its base classes (in Method
> Resolution Order, i.e. Parrot.__mro__) for a data descriptor (e.g. a
> property) named "colour". An instance can't override a data
> descriptor.

I did say it was an over-simplified description. I didn't think it was 
helpful to start talking about descriptors to a beginner :-)

For what it's worth, descriptors are both absolutely fundamental to how 
Python operates, and an advanced feature that newbies don't need to 
understand immediately,


-- 
Steven
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class variables [was Tutor Digest, Vol 118, Issue 99]

2013-12-21 Thread Steven D'Aprano
(I fixed the subject line for you.)

On Sat, Dec 21, 2013 at 02:53:28AM -0500, Keith Winston wrote:
> On Sat, Dec 21, 2013 at 2:14 AM,  wrote:
> 
> > I don't like the terms "class variable" and "instance variable". In the
> > Python community, these are usually called class and instance attributes
> > rather than variables or members.
> >
> 
> Hey Steven, that was a very generous explanation. Thanks! Very clear. I was
> floundering over the simple name/concept of attibute, and it had undermined
> my reading of other material. Your examples were extremely helpful. I think
> I understood everything you said (after a second reading). 

Glad to be of service!


> I keep hearing
> about how Python creates namespaces which I think are dictionaries, I'm
> going to have to look into that further to understand how some of this fits
> together.

Think of a typical family. Unless you're one of George Foreman's five 
sons all called George, chances are that everyone in the family has a 
different name. (Or at least a different nickname.) "Fred" in your 
family is not the same as "Fred" in my family. In this case, the family 
plays the role of a namespace: everyone inside the family has a unique 
name that they are known by, but people in different families can have 
the same name.

In general, a "namespace" is some sort of environment or container that 
holds identifiers (such as names, or ID numbers). Within a single 
namespace, all identifiers have to be unique, but two different 
namespaces can hold the same identifier. For example, in Python, each 
module is a namespace. If you have two files, say "spam.py" and 
"eggs.py", the two modules may include variables with the same name:

spam.thing = 23
eggs.thing = 42

Even though they are both called "thing", they live in different 
namespaces so they can have different values.

Python namespaces are usually dictionaries. The globals() function 
returns the global namespace, which is a dict. You will find all your 
global variables in it. Here's an example:

py> x = 23
py> d = globals()
py> d['x']
23
py> d['x'] = 42
py> x
42


(Note: operating directly on globals(), as I do in that example, is not 
a common thing to do. Python gives you the ability to do so, but it's 
quite rare to actually need it.)

Classes and instances also behave as namespaces. Both normally have a 
special attribute called "__dict__" (that's two underscores at the start 
and end of the name). Class.__dict__ holds the class attributes, 
including methods. The instance __dict__ holds the instance attributes.

Rather than access the __dict__ directly, it is nearly always better to 
use getattr and setattr functions. That is:

# don't do this
obj.__dict__['attribute'] = 23

# this is better
setattr(obj, 'attribute', 23)

# but this is even better
obj.attribute = 23


The main reason for using getattr and setattr is when you don't know the 
name of the attribute when you write the code, but only at runtime. For 
example:

name = get_some_name()  # returns some attribute name
getattr(obj, name)

You can't use obj.name, since that will return the attribute called 
literally "name". In this case, you want the attribute named *by* name 
instead -- if name == "colour", you want obj.colour, if name == "height", 
you want obj.height, and so on.


> I think that's where Python is going when you're talking about
> looking up attributes (and it would include methods too, unless they're
> still functions... maybe they're methods for instances and functions for
> classes? Ok, I don't get that part yet).

Methods and functions are another story, but in a nutshell, methods are 
just like functions except that they live inside classes, and when you 
call a method, it automatically gets the instance as the first argument. 
Confused? Here's an example, using a string method.

Strings have a method, replace, that works like this:

py> "the cat in the hat eats green ham".replace("cat", "dog")
'the dog in the hat eats green ham'


If replace were a function, we would write it something like this:

# simplified version
def replace(s, old, new):
...


and you would call it like this:


replace("the cat in the hat eats green ham", "cat", "dog")
=> returns "the dog in the hat eats green ham"


So you can think of the difference between methods and functions that 
methods use the syntax:

arg1.method(arg2, arg3, ...)

instead of:

function(arg1, arg2, arg3, ...)


There are other differences, but that is the most important one.



-- 
Steven
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class variables

2013-12-21 Thread eryksun
On Sat, Dec 21, 2013 at 2:14 AM, Steven D'Aprano  wrote:
>
> (Sometimes, people will call them "members", especially if they are used
> to C#. The meaning here is member as in an arm or leg, as in
> "dismember", not member in the sense of belonging to a group.)

A Python object isn't just a fixed-size block of data with members at
fixed offsets. It stores its data dynamically in a dict.

That said, CPython objects do have members as an implementation
detail, including class-defined __slots__. The member_descriptor type
is used to access members as attributes.

For example, the read-only __base__ attribute of a class uses the
following descriptor:

>>> vars(type)['__base__']


> Suppose we ask Python for "polly.colour". Python looks at the instance
> polly, and checks to see if it has an instance attribute called "polly".
> If it does, we're done. But if it doesn't, Python doesn't give up
> straight away, it next checks the class of polly, which is Parrot. Does
> Parrot have an attribute called "polly"? Yes it does, so that gets
> returned.

It first has to check Parrot and its base classes (in Method
Resolution Order, i.e. Parrot.__mro__) for a data descriptor (e.g. a
property) named "colour". An instance can't override a data
descriptor.

> So unlike *getting* an attribute, which searches both the instance
> and the class, *setting* or *deleting* an attribute stops at the
> instance.

Setting and deleting an attribute also has to start by searching the
class and bases for data descriptors.
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class variables

2013-12-20 Thread Steven D'Aprano
On Fri, Dec 20, 2013 at 02:04:49AM -0500, Keith Winston wrote:
> I am a little confused about class variables: I feel like I've repeatedly
> seen statements like this:

I don't like the terms "class variable" and "instance variable". In the 
Python community, these are usually called class and instance attributes 
rather than variables or members.

(Sometimes, people will call them "members", especially if they are used 
to C#. The meaning here is member as in an arm or leg, as in 
"dismember", not member in the sense of belonging to a group.)

Normally, we say that a string variable is a variable holding a string, 
a float variable is a variable holding a float, an integer variable is a 
variable holding an integer. So a class variable ought to be a variable 
holding a class, and an instance variable ought to be a variable holding 
an instance. In Python we can have both of those things!

Unlike Java, classes are "first-class citizens" and can be treated 
exactly the same as strings, floats, ints and other values. So a "class 
variable" would be something like this:

for C in list_of_classes:
# Here, C holds a class, and so we might call
# it a "class variable", not a string variable
do_something_with(variable)


> There is only one copy of the class variable and when any one object makes a
> change to a class variable, that change will be seen by all the other
> instances.
> Object variables are owned by each individual object/instance of the class.
> In this case, each object has its own copy

Talking about copies is not a good way to understand this. It might make 
sense to talk about copies in some other languages, but not in Python. 
(Or any of many languages with similar behaviour, like Ruby or Java.) 

I'm going to give you a simple example demonstrating why thinking about 
copies is completely the wrong thing to do here. If you already 
understand why "copies" is wrong, you can skip ahead here, but otherwise 
you need to understand this even though it doesn't directly answer your 
question.

Given a simple class, we can set an attribute on a couple of instances 
and see what happens. Copy and paste these lines into a Python 
interactive session, and see if you can guess what output the print will 
give:


class Test:
pass

spam = Test()
eggs = Test()

obj = []
spam.attribute = obj
eggs.attribute = obj
spam.attribute.append("Surprise!")

print(eggs.attribute)


If you think about *copies*, you might think that spam and eggs have 
their own independent copies of the empty list. But that's not what 
Python does. You don't have two copies of the list, you have a single 
list, and two independent references to it. (Actually, there are three: 
obj, spam.attribute, eggs.attribute.) But only one list, with three 
different names.

This is similar to people. For instance, the President of the USA is 
known as "Mr President" to his staff, "POTUS" to the military, "Barrack" 
to his wife Michelle, "Mr Obama" to historians and journalists, "Dad" to 
his children, and so forth. But they all refer to the same person. In a 
few years, Barrack Obama will stand down as president, and somebody else 
will be known as "Mr President" and "POTUS", but he'll still be 
"Barrack" to Michelle.

Python treats objects exactly the same. You can have lots of names for 
the same object. Some objects, like lists, can be modified in place. 
Other objects, like strings and ints, cannot be.

In Python, we refer to this system as "name binding". You have things 
which are names, like "obj", and we associate an object to that name. 
Another term for this is a "reference", in the generic sense that we 
"refer" to things.

So we can bind an object to a name:

obj = []

We can *unbind* the name as well:

del obj

In Python, assignment with = is name binding, and not copying:

spam.attribute = obj

does not make a copy of the list, it just makes "spam.attribute" and 
"obj" two different names for the same list. And likewise for 
"eggs.attribute".


Hopefully now you can understand why it is wrong to talk about "copies" 
here. In Python, you only get copies when you explicitly call a function 
which makes a copy, and never from = assignment (name binding).


Now let me get back to your original question:
 
> But when I test, I see some interesting things: first (and this is
> consistent with above) the class variables are created when the class is
> defined, and can be used even without any instances of the class being
> created.

Correct. Not only that, but class attributes will show up from instances 
as well:


py> class Parrot:
... colour = "green"
... def description(self):
... return "You see a %s coloured bird." % self.colour
...
py> polly = Parrot()
py> polly.description()
'You see a green coloured bird.'


> Second, initially confusing but maybe I understand... there are pointers to
> the class variables associated with every instance of the object, 

Don't think about pointers. That's too speci

Re: [Tutor] class variables

2013-12-20 Thread eryksun
On Fri, Dec 20, 2013 at 5:20 AM, Alan Gauld  wrote:
>
> Similarly if you have a name defined within the instance it will use that if
> not it will look in the class.

An instance can generally shadow class attributes, except properties
and other data descriptors defined by the class are given precedence
when looking up attributes:

>>> instance = Class()
>>> Class.pi = property(lambda s: 3.14)

>>> instance.pi
3.14
>>> instance.pi = 4
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: can't set attribute

The property is used even if you manually assign pi in the instance dict:

>>> vars(instance)['pi'] = 4
>>> vars(instance)
{'pi': 4}
>>> instance.pi
3.14
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class variables

2013-12-20 Thread Alan Gauld

On 20/12/13 07:04, Keith Winston wrote:


Class.pi == 3.14  # defined/set in the class def
instance.pi == 3.14  # initially
instance.pi = 4  # oops, changed it
Class.pi == 3.14  # still
Class.pi = "rhubarb"  # oops, there I go again
instance.pi == 4  # still

Sorry if I'm beating this to a pulp, I think I've got it...


You do have it.

Think of it like an extension to any other form of name look up.
The built in functions are available to you anywhere but you can 
override them in your code. Python  looks first to see if you have 
defined your own version, if you don't it looks in the built in

names.

Similarly if you have a name defined within the instance it will use 
that if not it will look in the class.


My personal rule for this is if you want the class variable always 
access it via the class rather than the instance.


But that falls down when processing a polymorphic collection where some 
instances may have instance variables and others only class variables.

So a loop like this

for obj in myMixedObjectList:
obj.someName = 42

Those instances that didn't have an instance var called someName
before, have one now. That may not be a good thing, especially
if the objects methods use self.someName to access the class
variable.

But these cases are relatively rare in my experience. Lists of
objects are usually more closely related than in the example above.

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.flickr.com/photos/alangauldphotos

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class variables

2013-12-20 Thread Dominik George
Hi,

> I am a little confused about class variables: I feel like I've repeatedly
> seen statements like this:

please take a look at the archives - this topic has been discussed on
this list recently.

-nik

-- 
* mirabilos is handling my post-1990 smartphone *
 Aaah, it vibrates! Wherefore art thou, demonic device??

PGP-Fingerprint: 3C9D 54A4 7575 C026 FB17  FD26 B79A 3C16 A0C4 F296


signature.asc
Description: Digital signature
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


[Tutor] class variables

2013-12-20 Thread Keith Winston
I am a little confused about class variables: I feel like I've repeatedly
seen statements like this:

There is only one copy of the class variable and when any one object makes a
change to a class variable, that change will be seen by all the other
instances.
Object variables are owned by each individual object/instance of the class.
In
this case, each object has its own copy

But when I test, I see some interesting things: first (and this is
consistent with above) the class variables are created when the class is
defined, and can be used even without any instances of the class being
created.

Second, initially confusing but maybe I understand... there are pointers to
the class variables associated with every instance of the object, but if I
assign THOSE variables new values, it crerates new, "local"/instance
variables.

So:
Class.pi == 3.14  # defined/set in the class def
instance.pi == 3.14  # initially
instance.pi = 4  # oops, changed it
Class.pi == 3.14  # still
Class.pi = "rhubarb"  # oops, there I go again
instance.pi == 4  # still

Sorry if I'm beating this to a pulp, I think I've got it... I'm just
confused because the way they are described feels a little confusing, but
maybe that's because I'm not taking into account how easy it is to create
local variables...
-- 
Keith
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class attribute error

2013-11-17 Thread Reuben
Hi,

Thanks for correcting me.
The solutions mentioned by Dominik and Alan have simplified the concept to
me now.

Regards,
Reuben


On Sun, Nov 17, 2013 at 5:25 AM, Dominik George  wrote:

> On Sat, Nov 16, 2013 at 09:13:13AM -0800, reutest wrote:
> > class myclass():
> >
> > def test(self):
> >   print "print this line"
> >
> >
> > if __name__ == '__main__':
> >   myclass.run()
>
> Is that a question?
>
> If I were to guess, I'd say you should have asked "Why does this say
> that myclass does not havea run method?". Then the simple answer is:
> Because, well, it doesn't! Why do you expect it to have one?
>
> -nik
>
> --
> Wer den Grünkohl nicht ehrt, ist der Mettwurst nicht wert!
>
> PGP-Fingerprint: 3C9D 54A4 7575 C026 FB17  FD26 B79A 3C16 A0C4 F296
>
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class attribute error

2013-11-16 Thread Alan Gauld

On 16/11/13 17:13, reutest wrote:

class myclass():

  def test(self):
print "print this line"


if __name__ == '__main__':
   myclass.run()



If you have a question it helps if you ask it rather than have us guess.

In this case I'm guessing you got an error and you are wondering why?

It's because you are calling the run() class method of myclass. And 
there is no such method.


If that's not your question please post again with a bit more of a clue 
about what you want to know.



--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.flickr.com/photos/alangauldphotos

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class attribute error

2013-11-16 Thread Dominik George
On Sat, Nov 16, 2013 at 09:13:13AM -0800, reutest wrote:
> class myclass():
>   
> def test(self):
>   print "print this line"
>   
> 
> if __name__ == '__main__':
>   myclass.run()

Is that a question?

If I were to guess, I'd say you should have asked "Why does this say
that myclass does not havea run method?". Then the simple answer is:
Because, well, it doesn't! Why do you expect it to have one?

-nik

-- 
Wer den Grünkohl nicht ehrt, ist der Mettwurst nicht wert!

PGP-Fingerprint: 3C9D 54A4 7575 C026 FB17  FD26 B79A 3C16 A0C4 F296


signature.asc
Description: Digital signature
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


[Tutor] Class attribute error

2013-11-16 Thread reutest
class myclass():

  def test(self):
print "print this line"


if __name__ == '__main__':
  myclass.run()



--
View this message in context: 
http://python.6.x6.nabble.com/Class-attribute-error-tp5039199.html
Sent from the Python - tutor mailing list archive at Nabble.com.
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class decorator question

2013-10-06 Thread Albert-Jan Roskam
- Original Message -

> From: Steven D'Aprano 
> To: tutor@python.org
> Cc: 
> Sent: Sunday, October 6, 2013 4:52 AM
> Subject: Re: [Tutor] class decorator question
> 
> On Sat, Oct 05, 2013 at 12:26:14PM -0700, Albert-Jan Roskam wrote:
> 
>>  >> On http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/ I 
> saw 
>>  >> a very cool and useful example of a class decorator. It 
> (re)implements 
>>  >> __str__ and __unicode__ in case Python 2 is used. For Python 3, 
> the 
>>  >> decorator does nothing. I wanted to generalize this decorator so 
> the 
>>  >> __str__ method under Python 2 encodes the string to an arbitrary 
>>  >> encoding. This is what I've created: 
> http://pastebin.com/vghD1bVJ.
>>  >> 
>>  >> It works, but the code is not very easy to understand, I am 
> affraid. 
>>  >
>>  >It's easy to understand, it's just doing it the wrong way. It 
> creates 
>>  >and subclass of your class, which it shouldn't do. 
>> 
>>  Why not? Because it's an unusual coding pattern? Or is it ineffecient?
> 
> It is both of those things. (Well, the inefficiency is minor.) My 
> main objection is that it is inelegant, like using a screwdriver as 
> a chisel instead of using a chisel -- even when it's "good 
> enough", 
> it's not something you want other people to see you doing if you 
> care about looking like a craftsman :-)

or use a shoe to hammer a nail in the wall... ;-)

> Another issue is to do with naming. In your example, you decorate Test. 
> What that means in practice is that you create a new class, Klass(Test), 
> throw away Test, and bind Klass to the top-level name Test. So in effect 
> you're doing this:
> 
> class Test # The undecorated version.
> 
> class Klass(Test)  # Subclass it inside the decorator.
> 
> Test = Klass  # throw away the original and re-use the variable name.
> 
> But classes, like functions, have *two* names. They have the name they 
> are bound to, the variable name (*usually* one of these, but sometimes 
> zero or two or more). And they have their own internal name:
> 
> Test.__name__
> => returns "Klass"
> 
> 
> This will make debugging unneccesarily confusing. If you use your 
> decorator three times:
> 
> @implements_to_string
> class Spam
> 
> @implements_to_string
> class Eggs
> 
> @implements_to_string
> class Cheese
> 
> 
> instances of all three of Spam, Eggs and Cheese will claim to be 
> instances of "Klass".

That would indeed be *very* confusing. 

> Now there is a simple work-around for this: inside the decorator, call
> 
> Klass.__name__ = cls.__name__ 
> 
> before returning. But that leads to another issue, where instances of 
> the parent, undecorated, class (if any!) and instances of the child, 
> decorated, class both claim to be from the same "Test" class. This is 
> more of theoretical concern, since you're unlikely to be instantiating 
> the undecorated parent class.
> 
> 
>>  I subclassed because I needed the encoding value in the decorator.
>>  But subclassing may indeed have been overkill.
> 
> Yes :-)
> 
> The encoding value isn't actually defined until long after the decorator 
> has finished doing its work, after the class is decorated, and an 
> instance is defined. So there is no encoding value used in the decorator 
> itself. The decorator can trivially refer to the encoding value, so long 
> as that doesn't actually get executed until after an instance is 
> created:
> 
> def decorate(cls):
>     def spam(self):
>         print(self.encoding)
>     cls.spam = spam
>     return cls
> 
> works fine without subclassing.

waah, why didn't I think of this? I've been making this way more complicated 
than needed. self.__dict__["encoding"] = self.encoding (see also below) was 
another way I considered to pass the encoding value from the class to its 
decorator. I even considered making a class decorator with arguments. All 
unnecesary. 
 
> 
>>  >Here's a better 
>>  >approach: inject the appropriate methods into the class directly. 
> Here's 
>>  >a version for Python 3:
> [...]
>>  >This avoids overwriting __str__ if it is already defined, and likewise 
>>  >for __bytes__.
>> 
>>  Doesn't a class always have __str__ implementation?
> 
> No. Where is the __str__ implementation here?
> 
> class X:
>     pass
> 
> This class defines no methods at all. Its *superclass*, object in Python 
> 3, defines methods such as __

Re: [Tutor] class decorator question

2013-10-06 Thread Mark Lawrence

On 06/10/2013 03:58, Steven D'Aprano wrote:

On Sun, Oct 06, 2013 at 01:06:18AM +0100, Alan Gauld wrote:

On 05/10/13 20:26, Albert-Jan Roskam wrote:


General question: I am using pastebin now. Is that okay,


For code as short as this it's probably best kept with the message.
But once you get to 100+ lines its more debatable and if you get
to 200+ lines I'd definitely say a pastebin is better.


If somebody is tempted to post 200+ lines here, they probably shouldn't.
Instead, they should read this:

http://sscce.org/




I totally agree.

--
Roses are red,
Violets are blue,
Most poems rhyme,
But this one doesn't.

Mark Lawrence

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class decorator question

2013-10-05 Thread Steven D'Aprano
On Sun, Oct 06, 2013 at 01:06:18AM +0100, Alan Gauld wrote:
> On 05/10/13 20:26, Albert-Jan Roskam wrote:
> 
> >General question: I am using pastebin now. Is that okay,
> 
> For code as short as this it's probably best kept with the message.
> But once you get to 100+ lines its more debatable and if you get
> to 200+ lines I'd definitely say a pastebin is better.

If somebody is tempted to post 200+ lines here, they probably shouldn't. 
Instead, they should read this:

http://sscce.org/


-- 
Steven
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class decorator question

2013-10-05 Thread Steven D'Aprano
On Sat, Oct 05, 2013 at 12:26:14PM -0700, Albert-Jan Roskam wrote:

> >> On http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/ I saw 
> >> a very cool and useful example of a class decorator. It (re)implements 
> >> __str__ and __unicode__ in case Python 2 is used. For Python 3, the 
> >> decorator does nothing. I wanted to generalize this decorator so the 
> >> __str__ method under Python 2 encodes the string to an arbitrary 
> >> encoding. This is what I've created: http://pastebin.com/vghD1bVJ.
> >> 
> >> It works, but the code is not very easy to understand, I am affraid. 
> >
> >It's easy to understand, it's just doing it the wrong way. It creates 
> >and subclass of your class, which it shouldn't do. 
> 
> Why not? Because it's an unusual coding pattern? Or is it ineffecient?

It is both of those things. (Well, the inefficiency is minor.) My 
main objection is that it is inelegant, like using a screwdriver as 
a chisel instead of using a chisel -- even when it's "good enough", 
it's not something you want other people to see you doing if you 
care about looking like a craftsman :-)

Another issue is to do with naming. In your example, you decorate Test. 
What that means in practice is that you create a new class, Klass(Test), 
throw away Test, and bind Klass to the top-level name Test. So in effect 
you're doing this:

class Test # The undecorated version.

class Klass(Test)  # Subclass it inside the decorator.

Test = Klass  # throw away the original and re-use the variable name.

But classes, like functions, have *two* names. They have the name they 
are bound to, the variable name (*usually* one of these, but sometimes 
zero or two or more). And they have their own internal name:

Test.__name__
=> returns "Klass"


This will make debugging unneccesarily confusing. If you use your 
decorator three times:

@implements_to_string
class Spam

@implements_to_string
class Eggs

@implements_to_string
class Cheese


instances of all three of Spam, Eggs and Cheese will claim to be 
instances of "Klass".

Now there is a simple work-around for this: inside the decorator, call

Klass.__name__ = cls.__name__ 

before returning. But that leads to another issue, where instances of 
the parent, undecorated, class (if any!) and instances of the child, 
decorated, class both claim to be from the same "Test" class. This is 
more of theoretical concern, since you're unlikely to be instantiating 
the undecorated parent class.


> I subclassed because I needed the encoding value in the decorator.
> But subclassing may indeed have been overkill.

Yes :-)

The encoding value isn't actually defined until long after the decorator 
has finished doing its work, after the class is decorated, and an 
instance is defined. So there is no encoding value used in the decorator 
itself. The decorator can trivially refer to the encoding value, so long 
as that doesn't actually get executed until after an instance is 
created:

def decorate(cls):
def spam(self):
print(self.encoding)
cls.spam = spam
return cls

works fine without subclassing.



> >Here's a better 
> >approach: inject the appropriate methods into the class directly. Here's 
> >a version for Python 3:
[...]
> >This avoids overwriting __str__ if it is already defined, and likewise 
> >for __bytes__.
> 
> Doesn't a class always have __str__ implementation?

No. Where is the __str__ implementation here?

class X:
pass

This class defines no methods at all. Its *superclass*, object in Python 
3, defines methods such as __str__. But you'll notice that I didn't call 

hasattr(cls, '__str__') 

since that will return True, due to object having a __str__ method. I 
called

'__str__' in cls.__dict__

which only returns True if cls explicitly defines a __str__ method.


> Nice, thanks Steven. I made a couple of versions after reading your 
> advise. The main change that I still had to somehow retrieve the 
> encoding value from the class to be decorated (decoratee?). I simply 
> stored it in __dict__. Here is the second version that I created: 
> http://pastebin.com/te3Ap50C. I tested it in Python 2 and 3. 

Not sufficiently :-) Your test class has problems. See below.



> The Test 
> class contains __str__ and __unicode__ which are renamed and redefined 
> by the decorator if Python 3 (or 4, or..) is used.
> 
> 
> General question: I am using pastebin now. Is that okay, given that 
> this is not part of the "memory" of the Python Tutor archive? It might 
> be annoying if people search the archives and get 404s if they try to 
> follow these links. Just in case I am also pasting the code below:

In my opinion, no it's not okay, particularly if your code is short 
enough to be posted here.

Just because a pserson has access to this mailing list doesn't 
necessarily mean they have access to pastebin. It might be blocked. The 
site might be down. They might object to websites that require 
Javascript (pastebin doesn't *require* it, but it's 

Re: [Tutor] class decorator question

2013-10-05 Thread Alan Gauld

On 05/10/13 20:26, Albert-Jan Roskam wrote:


General question: I am using pastebin now. Is that okay,


For code as short as this it's probably best kept with the message.
But once you get to 100+ lines its more debatable and if you get
to 200+ lines I'd definitely say a pastebin is better.


from __future__ import print_function
import sys

def decorate(cls):
 print("decorate called")
 if sys.version_info[0] > 2:
 cls.__dict__["__str__"].__name__ = '__bytes__'
 cls.__dict__["__unicode__"].__name__ = '__str__'
 cls.__bytes__ = cls.__dict__["__str__"]
 cls.__str__ = cls.__dict__["__unicode__"]
 return cls

@decorate
class Test(object):

 def __init__(self):
 self.__dict__["encoding"] = self.encoding

 def __str__(self):
 return "str called".encode(self.encoding)

 def __unicode__(self):
 return "unicode called"

 @property
 def encoding(self):
 """In reality this method extracts the encoding from a file"""
 return "utf-8" # rot13 no longer exists in Python3

if __name__ == "__main__":
 t = Test()
 if sys.version_info[0] == 2:
 print(unicode(t))
 print(str(t))


--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.flickr.com/photos/alangauldphotos

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class decorator question

2013-10-05 Thread Albert-Jan Roskam
___

> From: Steven D'Aprano 
>To: tutor@python.org 
>Sent: Saturday, October 5, 2013 3:14 PM
>Subject: Re: [Tutor] class decorator question
>
>On Sat, Oct 05, 2013 at 05:33:46AM -0700, Albert-Jan Roskam wrote:
>> Hi,
>> 
>> On http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/ I saw 
>> a very cool and useful example of a class decorator. It (re)implements 
>> __str__ and __unicode__ in case Python 2 is used. For Python 3, the 
>> decorator does nothing. I wanted to generalize this decorator so the 
>> __str__ method under Python 2 encodes the string to an arbitrary 
>> encoding. This is what I've created: http://pastebin.com/vghD1bVJ.
>> 
>> It works, but the code is not very easy to understand, I am affraid. 
>
>It's easy to understand, it's just doing it the wrong way. It creates 
>and subclass of your class, which it shouldn't do. 



Why not? Because it's an unusual coding pattern? Or is it ineffecient?
I subclassed because I needed the encoding value in the decorator.
But subclassing may indeed have been overkill.



Here's a better 
>approach: inject the appropriate methods into the class directly. Here's 
>a version for Python 3:
>
>
>def decorate(cls):
>    if '__str__' not in cls.__dict__:
>        # inject __str__ method
>        def __str__(self):
>            ...
>        cls.__str__ = __str__
>
>    if '__bytes__' not in cls.__dict__:
>        # like above
>
>    return cls
>
>
>This avoids overwriting __str__ if it is already defined, and likewise 
>for __bytes__.


Doesn't a class always have __str__ implementation?

>>> class Foo(object): pass
>>> f = Foo()
>>> f.__str__

>>> Foo.__str__



>>> 
>> Or is it? And I have no idea how to call the class Klass. Maybe 
>> reimplements_Test? Is this a good approach, or can this be done in an 
>> easier way? I would *really* like keep statements "if 
>> sys.version_info[0] == 3..." separate from the "main" code. Also, 
>> learning about class decorators is cool ;-). So the code below... 
>> mehhh  no sir, I don't like it.

Btw, that was a quote: http://www.youtube.com/watch?v=dQ3acvz5LfI ;-)

>> 
>> 
>> def __str__(self):
>> 
>>     if sys.version_info[0] == 3:
>>         blah
>>     else:
>>         bleh
>>   
>> if sys.version_info[0] == 2:
>>     def __unicode__(self):
>>     blh
>
>
>That performs the version check every time the __str__ method is called. 


Good point.

>Better would be something like this:
>
>if sys.version_info[0] == 2:
>    def __str__(self):
>        ...
>
>    def __unicode__(self):
>        ...
>
>else:
>    def __bytes__(self):
>        ...
>
>    def __str__(self):
>        ...
>
>If you don't like repeating the code twice, once for version 2 and once 
>for version 3, you may be able to define the methods once, then rename 
>them, something like this:
>
># Assume version 3
>def __str__(self):
>    ...
>
>def __bytes__(self):
>    ...
>
>if sys.version_info[0] == 2:
>    __str__.__name__ = '__unicode__'
>    __bytes.__name__ = '__str__'
>    # Inject into the class, as above.
>    cls.__unicode__ = __str__
>    cls.__str__ = __bytes__
>
>else:
>    cls.__str__ = __str__
>    cls.__bytes__ = __bytes__
>
>
>Combining this with the decorator is left for you :-)

Nice, thanks Steven. I made a couple of versions after reading your advise. The 
main change that I still had to somehow retrieve the encoding value from the 
class to be decorated (decoratee?). I simply stored it in __dict__. Here is the 
second version that I created: http://pastebin.com/te3Ap50C. I tested it in 
Python 2 and 3. The Test class contains __str__ and __unicode__ which are 
renamed and redefined by the decorator if Python 3 (or 4, or..) is used.


General question: I am using pastebin now. Is that okay, given that this is not 
part of the "memory" of the Python Tutor archive? It might be annoying if 
people search the archives and get 404s if they try to follow these links. Just 
in case I am also pasting the code below:

from __future__ import print_function
import sys
    
def decorate(cls):
    print("decorate called")
    if sys.version_info[0] > 2:
    cls.__dict__["__str__"].__name__ = '__bytes__'
    cls.__dict__["__unicode__"].__name__ = '__str__'
    cls.__bytes__ = cls.__dict__["__str__"]
    cls.__str__ = cls.__dict__["__unicode__"]  
    return cls

@decorate
cl

Re: [Tutor] class decorator question

2013-10-05 Thread Steven D'Aprano
On Sat, Oct 05, 2013 at 05:33:46AM -0700, Albert-Jan Roskam wrote:
> Hi,
> 
> On http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/ I saw 
> a very cool and useful example of a class decorator. It (re)implements 
> __str__ and __unicode__ in case Python 2 is used. For Python 3, the 
> decorator does nothing. I wanted to generalize this decorator so the 
> __str__ method under Python 2 encodes the string to an arbitrary 
> encoding. This is what I've created: http://pastebin.com/vghD1bVJ.
> 
> It works, but the code is not very easy to understand, I am affraid. 

It's easy to understand, it's just doing it the wrong way. It creates 
and subclass of your class, which it shouldn't do. Here's a better 
approach: inject the appropriate methods into the class directly. Here's 
a version for Python 3:


def decorate(cls):
if '__str__' not in cls.__dict__:
# inject __str__ method
def __str__(self):
...
cls.__str__ = __str__

if '__bytes__' not in cls.__dict__:
# like above

return cls


This avoids overwriting __str__ if it is already defined, and likewise 
for __bytes__.


> Or is it? And I have no idea how to call the class Klass. Maybe 
> reimplements_Test? Is this a good approach, or can this be done in an 
> easier way? I would *really* like keep statements "if 
> sys.version_info[0] == 3..." separate from the "main" code. Also, 
> learning about class decorators is cool ;-). So the code below... 
> mehhh  no sir, I don't like it.
> 
> 
> def __str__(self):
> 
>     if sys.version_info[0] == 3:
>         blah
>     else:
>         bleh
>   
> if sys.version_info[0] == 2:
>     def __unicode__(self):
>     blh


That performs the version check every time the __str__ method is called. 
Better would be something like this:

if sys.version_info[0] == 2:
def __str__(self):
...

def __unicode__(self):
...

else:
def __bytes__(self):
...

def __str__(self):
...



If you don't like repeating the code twice, once for version 2 and once 
for version 3, you may be able to define the methods once, then rename 
them, something like this:


# Assume version 3
def __str__(self):
...

def __bytes__(self):
...

if sys.version_info[0] == 2:
__str__.__name__ = '__unicode__'
__bytes.__name__ = '__str__'
# Inject into the class, as above.
cls.__unicode__ = __str__
cls.__str__ = __bytes__

else:
cls.__str__ = __str__
cls.__bytes__ = __bytes__


Combining this with the decorator is left for you :-)



-- 
Steven
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


[Tutor] class decorator question

2013-10-05 Thread Albert-Jan Roskam
Hi,

On http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/ I saw a very 
cool and useful example of a class decorator. It (re)implements __str__ and 
__unicode__ in case Python 2 is used. For Python 3, the decorator does nothing. 
I wanted to generalize this decorator so the __str__ method under Python 2 
encodes the string to an arbitrary encoding. This is what I've created: 
http://pastebin.com/vghD1bVJ.

It works, but the code is not very easy to understand, I am affraid. Or is it? 
And I have no idea how to call the class Klass. Maybe reimplements_Test? Is 
this a good approach, or can this be done in an easier way? I would *really* 
like keep statements "if sys.version_info[0] == 3..." separate from the "main" 
code. Also, learning about class decorators is cool ;-). So the code below... 
mehhh  no sir, I don't like it.


def __str__(self):

    if sys.version_info[0] == 3:
        blah
    else:
        bleh
  
if sys.version_info[0] == 2:
    def __unicode__(self):
    blh


 
Regards,
Albert-Jan


~~
All right, but apart from the sanitation, the medicine, education, wine, public 
order, irrigation, roads, a 
fresh water system, and public health, what have the Romans ever done for us?
~~ ___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class data member and objects of class in python

2013-09-12 Thread Dave Angel
On 12/9/2013 05:10, zubair alam wrote:


> class PizzaShop():    pizza_stock = 
> 10    def get_pizza(self):        while 
> PizzaShop.pizza_stock:            PizzaShop.pizza_stock -= 
> 1            yield "take yours pizza order, total pizzas left 
> {}".format(PizzaShop.pizza_stock)
> mypizza_shop = PizzaShop()pizza_order = 
> mypizza_shop.get_pizza() # print 
> "{}".format(repr(pizza_order.next()))for 
> order in pizza_order:
>print 
> "{}".format(repr(order))domino_pizza_store
>  = mypizza_shop.get_pizza()print 
> "{}".format(repr(domino_pizza_store.next()))
> mypizza_shop.pizza_stock = 
> 10domino_pizza_store = 
> mypizza_shop.get_pizza()print 
> "{}".format(repr(domino_pizza_store.next()))
> can't we again use the same object mypizza_shop once its 
> generator is exhausted class="gmail_quote">On Thu, Sep 12, 2013 at 6:53 AM, Marc Tompkins  dir="ltr"> target="_blank">marc.tompk...@gmail.com> wrote:

Please use text email, not hmtl.  The indentation of your program was
messed up in places, and I can't tell whether it was you or the email
program that messed it up.  This is a text newgroup, and html doesn't
work reliably.

As Alan has said, you're confusing class attributes with instance
attributes.  But I wonder if the mistake is actually the reverse of what
he says.

Do you intend that an instance of PizzaShop refers to a particul pizza
shop, and that it has its own inventory, independent of all other pizza
shop instances?  in that case all use of the class attribute
pizza_stock = 10 is bogus.

To re-iterate the other point Alan made, an iterator is *required* to
continue to throw Stopiteration once its exhausted and has thrown it
once, even if new items show up that it could have used.

But you can readily make a new iterator from the same mypizza_shop, once
you set its pizza_stock to a nonzero value.

-- 
DaveA


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class data member and objects of class in python

2013-09-12 Thread Alan Gauld

On 12/09/13 10:10, zubair alam wrote:

class PizzaShop():
 pizza_stock = 10
 def get_pizza(self):
 while PizzaShop.pizza_stock:
 PizzaShop.pizza_stock -= 1
 yield "take yours pizza order, total pizzas left
{}".format(PizzaShop.pizza_stock)

mypizza_shop = PizzaShop()
pizza_order = mypizza_shop.get_pizza()

for order in pizza_order:
print "{}".format(repr(order))


You might as well just use

print order


domino_pizza_store = mypizza_shop.get_pizza()
print "{}".format(repr(domino_pizza_store.next()))

mypizza_shop.pizza_stock = 10


This preobably isn't doing what you think it is.
This is creating a new instance attribute in the
mypizza_shop instance it is not resetting the
class attribute. For that you would need to use

PizzaShop.pizza_stock = 10


can't we again use the same object mypizza_shop

> once its generator is exhausted

You can't use the same iterator again but you can
get a new one. But your problem here is that you have
not reset the class stock level.

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.flickr.com/photos/alangauldphotos

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class data member and objects of class in python

2013-09-12 Thread zubair alam
class PizzaShop():
pizza_stock = 10
def get_pizza(self):
while PizzaShop.pizza_stock:
PizzaShop.pizza_stock -= 1
yield "take yours pizza order, total pizzas left
{}".format(PizzaShop.pizza_stock)

mypizza_shop = PizzaShop()
pizza_order = mypizza_shop.get_pizza()
# print "{}".format(repr(pizza_order.next()))

for order in pizza_order:
print "{}".format(repr(order))

domino_pizza_store = mypizza_shop.get_pizza()
print "{}".format(repr(domino_pizza_store.next()))

mypizza_shop.pizza_stock = 10

domino_pizza_store = mypizza_shop.get_pizza()
print "{}".format(repr(domino_pizza_store.next()))


can't we again use the same object mypizza_shop once its generator is
exhausted


On Thu, Sep 12, 2013 at 6:53 AM, Marc Tompkins wrote:

> On Wed, Sep 11, 2013 at 5:40 AM, zubair alam wrote:
>
>> i am learning how a __class__ data member behaves in python as compared
>> to static data member in java, but following code is throwing error
>>
>>
>> class PizzaShop():
>> pizza_stock = 10
>> def get_pizza(self):
>> while not PizzaShop.pizza_stock:
>> PizzaShop.pizza_stock -= 1
>> yield "take yours pizza order, total pizzas left
>> {}".format(PizzaShop.pizza_stock)
>>
>> mypizza_shop = PizzaShop()
>> pizza_order = mypizza_shop.get_pizza() # iterator is obtained
>> print "a pizza pls!! {}:".format(pizza_order.next())
>> print "a pizza pls!! {}:".format(pizza_order.next())
>>
>> output:
>> Traceback (most recent call last):
>>   File "/home/scott/pythonfiles/core_python/pizza.py", line 10, in
>> 
>> print "a pizza pls!! {}:".format(pizza_order.next())
>> StopIteration
>>
>>
>> don't know where i am doing mistakeany help will be appreciated... i
>> have other questions on based on this class
>>
>>
>
> Change "while not PizzaShop.pizza_stock:" to "while
> PizzaShop.pizza_stock:"; I get the following output:
>
>> a pizza pls!! take yours pizza order, total pizzas left 9:
>> a pizza pls!! take yours pizza order, total pizzas left 8:
>>
>
>
>
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class data member and objects of class in python

2013-09-12 Thread Felix Dietrich
> i am learning how a __class__ data member behaves in python as
> compared to static data member in java [...]

The error is not related to class variables. Also could you elaborate on
what you intended to find out with this snippet?

> class PizzaShop():
> pizza_stock = 10
> 
> def get_pizza(self):
> while not PizzaShop.pizza_stock:
> PizzaShop.pizza_stock -= 1
> yield "take yours pizza order, total pizzas left 
> {}".format(PizzaShop.pizza_stock)

The condition in the while loop is wrong. bool(PizzaShop.pizza_stock) is
True for all values but 0. (All numbers but 0 are considered True.) The
while loop does its commands while the condition holds True. When you do

not PizzaShop.pizza_stock

it will return False for values other than 0, therefor the loop is never
run and on exit of get_pizza it raises StopIteration to indicate that
there are no more values to be yielded.

> mypizza_shop = PizzaShop()
> pizza_order = mypizza_shop.get_pizza() # iterator is obtained
> print "a pizza pls!! {}:".format(pizza_order.next())
> print "a pizza pls!! {}:".format(pizza_order.next())

You might want to catch StopIteration here so that you can handle the
case that the shop runs out of the initial stack of pizzas. ;)

--
Felix Dietrich
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class data member and objects of class in python

2013-09-11 Thread Marc Tompkins
On Wed, Sep 11, 2013 at 5:40 AM, zubair alam wrote:

> i am learning how a __class__ data member behaves in python as compared to
> static data member in java, but following code is throwing error
>
>
> class PizzaShop():
> pizza_stock = 10
> def get_pizza(self):
> while not PizzaShop.pizza_stock:
> PizzaShop.pizza_stock -= 1
> yield "take yours pizza order, total pizzas left
> {}".format(PizzaShop.pizza_stock)
>
> mypizza_shop = PizzaShop()
> pizza_order = mypizza_shop.get_pizza() # iterator is obtained
> print "a pizza pls!! {}:".format(pizza_order.next())
> print "a pizza pls!! {}:".format(pizza_order.next())
>
> output:
> Traceback (most recent call last):
>   File "/home/scott/pythonfiles/core_python/pizza.py", line 10, in 
> print "a pizza pls!! {}:".format(pizza_order.next())
> StopIteration
>
>
> don't know where i am doing mistakeany help will be appreciated... i
> have other questions on based on this class
>
>

Change "while not PizzaShop.pizza_stock:" to "while
PizzaShop.pizza_stock:"; I get the following output:

> a pizza pls!! take yours pizza order, total pizzas left 9:
> a pizza pls!! take yours pizza order, total pizzas left 8:
>
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


[Tutor] class data member and objects of class in python

2013-09-11 Thread zubair alam
i am learning how a __class__ data member behaves in python as compared to
static data member in java, but following code is throwing error


class PizzaShop():
pizza_stock = 10
def get_pizza(self):
while not PizzaShop.pizza_stock:
PizzaShop.pizza_stock -= 1
yield "take yours pizza order, total pizzas left
{}".format(PizzaShop.pizza_stock)

mypizza_shop = PizzaShop()
pizza_order = mypizza_shop.get_pizza() # iterator is obtained
print "a pizza pls!! {}:".format(pizza_order.next())
print "a pizza pls!! {}:".format(pizza_order.next())

output:
Traceback (most recent call last):
  File "/home/scott/pythonfiles/core_python/pizza.py", line 10, in 
print "a pizza pls!! {}:".format(pizza_order.next())
StopIteration


don't know where i am doing mistakeany help will be appreciated... i
have other questions on based on this class
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class-based generator

2013-02-18 Thread Peter Otten
Michael O'Leary wrote:

> I wrote some code to create tasks to be run in a queue based system last
> week. It consisted of a big monolithic function that consisted of two
> parts: 1) read data from a file and create dictionaries and lists to
> iterate through
> 2) iterate through the lists creating a job data file and a task for the
> queue one at a time until all of the data is dealt with
> 
> My boss reviewed my code and said that it would be more reusable and
> Pythonic if I refactored it as a generator that created job data files and
> iterated by calling the generator and putting a task on the queue for each
> job data file that was obtained.
> 
> This made sense to me, and since the code does a bunch of conversion of
> the data in the input file(s) to make it easier and faster to iterate
> through the data, I decided to create a class for the generator and put
> that conversion code into its __init__ function. So the class looked like
> this:
> 
> class JobFileGenerator:
> def __init__(self, filedata, output_file_prefix, job_size):
> 
> 
> def next(self):
> while :
> 
> 
> The problem is that the generator object is not created until you call
> next(), so the calling code has to look like this:
> 
> gen = JobFileGenerator(data, "output_", 20).next()
> for datafile in gen.next():
> 
> 
> This code works OK, but I don't like that it needs to call next() once to
> get a generator and then call next() again repeatedly to get the data for
> the jobs. If I were to write this without a class as a single generator
> function, it would not have to do this, but it would have the monolithic
> structure that my boss objected to.
> 
> Would it work to do this:
> 
> for datafile in JobFileGenerator(data, "output_", 20).next():
> 
> 
> or would that cause the JobFileGenerator's __init__ function to be called
> more than once? Are there examples I could look at of generator functions
> defined on classes similar to this, or is it considered a bad idea to mix
> the two paradigms?
> Thanks,
> Mike


You are abusing the next method; it is called once to build a generator. The 
convention for that is to use either a descriptive name (jobs() or somesuch) 
or __iter__():

class JobFile:
def __init__(self, filedata, output_file_prefix, job_size):

def __iter__(self):
while :



for job in JobFile(data, "output_", 20):


Here the generator is created by the implicit call to JobFile.__iter__() at 
the start of the for loop. Subsequent iterations call next() on the 
generator returned by that call.

If you want the class itself to generate items you need a different 
approach:

class JobFileIter:
def __init__(self, filedata, output_file_prefix, job_size):

self._done = False
def __iter__(self):
return self
def next(self):
if self._done or :
self._done = True
raise StopIteration
return 


for job in JobFileIter(data, "output_", 20):


Here __iter__() returns the JobFileIter instance, so for every iteration of 
the for loop JobFileIter.next() will be called -- until a StopIteration is 
raised.

That said, it is often sufficient to refactor complex code into a few 
dedicated functions -- Python is not Java, after all.

PS I'm assuming Python 2 -- for Python 3 the next() method must be replaced 
by __next__().

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class-based generator

2013-02-18 Thread Oscar Benjamin
On 18 February 2013 07:36, Michael O'Leary  wrote:
> I wrote some code to create tasks to be run in a queue based system last
> week. It consisted of a big monolithic function that consisted of two parts:
> 1) read data from a file and create dictionaries and lists to iterate
> through
> 2) iterate through the lists creating a job data file and a task for the
> queue one at a time until all of the data is dealt with
>
> My boss reviewed my code and said that it would be more reusable and
> Pythonic if I refactored it as a generator that created job data files and
> iterated by calling the generator and putting a task on the queue for each
> job data file that was obtained.
>
> This made sense to me, and since the code does a bunch of conversion of the
> data in the input file(s) to make it easier and faster to iterate through
> the data, I decided to create a class for the generator and put that
> conversion code into its __init__ function. So the class looked like this:

It's not a "generator" if you create a class for it. Your class is
(trying to be) an iterator.

> class JobFileGenerator:
> def __init__(self, filedata, output_file_prefix, job_size):
> 
>
> def next(self):
> while :
> 

next() should return a single item not a generator that yields items.
If you perhaps rename the next function as __iter__ then it will be a
proper iterator.

I suspect however that your boss just wants you to write a single
generator function rather than an iterator class. For example:

def generate_jobs():

while :
yield 

for job in generate_jobs():

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


[Tutor] Class-based generator

2013-02-17 Thread Michael O'Leary
I wrote some code to create tasks to be run in a queue based system last
week. It consisted of a big monolithic function that consisted of two parts:
1) read data from a file and create dictionaries and lists to iterate
through
2) iterate through the lists creating a job data file and a task for the
queue one at a time until all of the data is dealt with

My boss reviewed my code and said that it would be more reusable and
Pythonic if I refactored it as a generator that created job data files and
iterated by calling the generator and putting a task on the queue for each
job data file that was obtained.

This made sense to me, and since the code does a bunch of conversion of the
data in the input file(s) to make it easier and faster to iterate through
the data, I decided to create a class for the generator and put that
conversion code into its __init__ function. So the class looked like this:

class JobFileGenerator:
def __init__(self, filedata, output_file_prefix, job_size):


def next(self):
while :


The problem is that the generator object is not created until you call
next(), so the calling code has to look like this:

gen = JobFileGenerator(data, "output_", 20).next()
for datafile in gen.next():


This code works OK, but I don't like that it needs to call next() once to
get a generator and then call next() again repeatedly to get the data for
the jobs. If I were to write this without a class as a single generator
function, it would not have to do this, but it would have the monolithic
structure that my boss objected to.

Would it work to do this:

for datafile in JobFileGenerator(data, "output_", 20).next():


or would that cause the JobFileGenerator's __init__ function to be called
more than once? Are there examples I could look at of generator functions
defined on classes similar to this, or is it considered a bad idea to mix
the two paradigms?
Thanks,
Mike
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] 'class' for someone with no object oriented programming experience

2012-09-11 Thread Brannon, Terrence


From: Tutor 
[mailto:tutor-bounces+terrence.brannon=bankofamerica@python.org] On Behalf 
Of Art Scheel
Sent: Tuesday, September 11, 2012 3:34 PM
To: tutor@python.org
Subject: [Tutor] 'class' for someone with no object oriented programming 
experience


Are there any better resources for learning classes for someone who's never 
touched object oriented programming in the past besides basic interpretation 
for debugging purposes?

[Terrence Brannon] Why don't you read this 
http://docs.python.org/tutorial/classes.html and write to this list regarding 
the first thing you don't understand.


--
This message w/attachments (message) is intended solely for the use of the 
intended recipient(s) and may contain information that is privileged, 
confidential or proprietary. If you are not an intended recipient, please 
notify the sender, and then please delete and destroy all copies and 
attachments, and be advised that any review or dissemination of, or the taking 
of any action in reliance on, the information contained in or attached to this 
message is prohibited. 
Unless specifically indicated, this message is not an offer to sell or a 
solicitation of any investment products or other financial product or service, 
an official confirmation of any transaction, or an official statement of 
Sender. Subject to applicable law, Sender may intercept, monitor, review and 
retain e-communications (EC) traveling through its networks/systems and may 
produce any such EC to regulators, law enforcement, in litigation and as 
required by law. 
The laws of the country of each sender/recipient may impact the handling of EC, 
and EC may be archived, supervised and produced in countries other than the 
country in which you are located. This message cannot be guaranteed to be 
secure or free of errors or viruses. 

References to "Sender" are references to any subsidiary of Bank of America 
Corporation. Securities and Insurance Products: * Are Not FDIC Insured * Are 
Not Bank Guaranteed * May Lose Value * Are Not a Bank Deposit * Are Not a 
Condition to Any Banking Service or Activity * Are Not Insured by Any Federal 
Government Agency. Attachments that are part of this EC may have additional 
important disclosures and disclaimers, which you should read. This message is 
subject to terms available at the following link: 
http://www.bankofamerica.com/emaildisclaimer. By messaging with Sender you 
consent to the foregoing.
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class definition confusion

2012-02-15 Thread Mark Lawrence

On 15/02/2012 18:35, Hugo Arts wrote:
[snip]


An __init__ might seem like it's special in some way, declaring
attributes. But it's not, really, it's just another method that gets
passed the object it is called on (that would be "self"). It's only
special because it gets called when an object is created, so generally
an object is initialized there and attributes are assigned (hence the
name "init").'

HTH,
Hugo
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


To the OP.

Note that __init__ is an initialiser and not a constructor which is 
__new__, see e.g. 
http://mail.python.org/pipermail/tutor/2008-April/061426.html


--
Cheers.

Mark Lawrence.

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class definition confusion

2012-02-15 Thread Mark Lawrence

On 15/02/2012 18:14, Sivaram Neelakantan wrote:


I was under the impression that you have to define the attributes of
the class before using it in an instance.  Following the book
'thinking in Python',


class Point:

... """pts in 2d space"""
...

print Point

__main__.Point

b = Point()
b.x =3
b.y =4
print b.y

4




Why is it not throwing an error?  This is confusing me a bit.

  sivaram
  --

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor



Your impression is incorrect.  This type of behaviour is allowed because 
of Python's dynamic nature, so the following is fine.


>>> class Point:
... """pts in 2d space"""
... 
>>> b = Point()
>>> b.x = 3
>>> b.y = 4
>>> del b.x
>>> del b.y
>>> b.l = 5
>>> b.m = 6
>>> print b, b.l, b.m
<__main__.Point instance at 0x02FB89B8> 5 6

Also be careful of your terminology.  Here we are discussing instance 
attributes.  Class attributes are different in that they are are shared 
at the class level so.


>>> class Point:
... """pts in 2d space"""
... x = 3
... y = 4
... 
>>> a = Point()
>>> b = Point()
>>> a.x
3
>>> b.y
4

HTH.

--
Cheers.

Mark Lawrence.

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class definition confusion

2012-02-15 Thread Sivaram Neelakantan
On Thu, Feb 16 2012,Alan Gauld wrote:


[snipped 19 lines]

> Python allows instance attributes to be added at runtime.
> In general this is a bad idea IMHO, a dictionary would probably
> be more appropriate, but there can, very occasionally, be valid
> uses for it.

Thanks for that, I kept thinking that the author had made some typos
in the book and was getting progressively confused, till I tried it at
the prompt.

 sivaram
 -- 

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class definition confusion

2012-02-15 Thread Hugo Arts
On Wed, Feb 15, 2012 at 7:14 PM, Sivaram Neelakantan
 wrote:
>
> I was under the impression that you have to define the attributes of
> the class before using it in an instance.  Following the book
> 'thinking in Python',
>
 class Point:
> ...     """pts in 2d space"""
> ...
 print Point
> __main__.Point
 b = Point()
 b.x =3
 b.y =4
 print b.y
> 4

>
> Why is it not throwing an error?  This is confusing me a bit.
>

Python is different from static languages like C++. You can add and
remove attributes from objects at any time. You do not have to
declare, in your class, what kind of attributes it has.

An __init__ might seem like it's special in some way, declaring
attributes. But it's not, really, it's just another method that gets
passed the object it is called on (that would be "self"). It's only
special because it gets called when an object is created, so generally
an object is initialized there and attributes are assigned (hence the
name "init").'

HTH,
Hugo
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class definition confusion

2012-02-15 Thread Alan Gauld

On 15/02/12 18:14, Sivaram Neelakantan wrote:


I was under the impression that you have to define the attributes of
the class before using it in an instance.


Only in some languages. Python is not one of those.


class Point:

... """pts in 2d space"""
...

b = Point()
b.x =3
b.y =4
print b.y

4




Why is it not throwing an error?  This is confusing me a bit.


Python allows instance attributes to be added at runtime.
In general this is a bad idea IMHO, a dictionary would probably
be more appropriate, but there can, very occasionally, be valid
uses for it.

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


[Tutor] Class definition confusion

2012-02-15 Thread Sivaram Neelakantan

I was under the impression that you have to define the attributes of
the class before using it in an instance.  Following the book
'thinking in Python',

>>> class Point:
... """pts in 2d space"""
...
>>> print Point
__main__.Point
>>> b = Point()
>>> b.x =3
>>> b.y =4
>>> print b.y
4
>>>

Why is it not throwing an error?  This is confusing me a bit.

 sivaram
 -- 

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class Nesting

2012-02-06 Thread Steven D'Aprano
On Mon, Feb 06, 2012 at 08:17:05PM -0500, Greg Nielsen wrote:
[...]
>  So here is the problem, to create an object, you need to assign it to
> a variable, and you need to know what that variable is to call upon it
> later, so to have a object build a second object, it would need to somehow
> create a variable name, and you would somehow have to know what name it
> picked. Unless perhaps you had a Star Cluster list which had all of your
> created Star System objects, each with their own list of Planets which you
> could use list to call upon maybe

Yes, that's exactly the way to do it. Rather than assigning each object to 
a name:

cluster1 = StarCluster()
cluster2 = StarCluster()
...


you can work with a list of clusters:

clusters = [StarCluster(), StarCluster(), ...]


You can then operate on then one at a time. Say you want to do something to
the 3rd cluster. Remembering that Python starts counting positions at zero,
you would write something like:

clusters[2].name = "Local Cluster 12345"  # give the cluster a name

If your StarCluster objects are mutable (and if you don't know what that 
means, don't worry about it, by default all classes are mutable), you can 
grab a temporary reference to a cluster while working on it:

for cluster in clusters:  # work on each one sequentially
if cluster.stars == []:
print("Cluster %s has no stars." % cluster.name)

Here I have assumed that each cluster is given a list of stars. Something 
like this:

class StarCluster(object):
def __init__(self):
self.name = "no name yet"
self.stars = []
def add_star(self, *args, **kw_args):
self.stars.append(Star(*args, **kw_args))


Here I have given the StarCluster a method, "add_star", which takes an 
arbitrary 
set of arguments, passes them on to the Star class, and adds the resultant 
star to the list.

class Star(object):
def __init__(self, name="no name yet", kind="red giant", planets=None):
if planets is None:
planets = []
self.planets = planets
self.name = name
self.kind = kind


sol = Star(
"Sol", "yellow dwarf", 
['Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter', 'Saturn', 
 'Uranus', 'Neptune']  # ha ha, Pluto can bite me
)


I hope this helps,



-- 
Steven

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class Nesting

2012-02-06 Thread Dave Angel

On 02/06/2012 08:17 PM, Greg Nielsen wrote:

Hello List,

  My name is Greg, and while working on a project I've come across a
rather interesting problem. I'm trying to create a rough model of a star
cluster and all of the stars and planets contained within. Kind of a cool
project; hopefully it should work a little like this. I create a Star
Cluster object, which goes through a list of positions and decides if it
should build a Star System there. If it does, it then creates a Star System
object at that position which in turn calls upon and creates several Planet
objects to reside inside of it. All in all, about 64 positions to check, on
average 24 Star Systems, each with between 2 and 9 planets.
  So here is the problem, to create an object, you need to assign it to
a variable, and you need to know what that variable is to call upon it
later, so to have a object build a second object, it would need to somehow
create a variable name, and you would somehow have to know what name it
picked. Unless perhaps you had a Star Cluster list which had all of your
created Star System objects, each with their own list of Planets which you
could use list to call upon maybe
  I have a general grasp on the idea of nesting and calling upon objects
which you don't know the name of, but this goes far beyond my level of
understanding. Can anyone shed some light on how this would work, or
perhaps point me in the right direction of some documentation on this?
Thanks for the help, and I hope this is not too difficult of a question.

Greg



Since you talk of creating a StarCluster object, presumably you know how 
to make a class.  So in the class definition, you can define attributes 
that each instance has.  One of those attributes can be a list.  So the 
list has a name, but not the individual items in the list.


Generally, it's best to create an empty list attribute in the 
initializer of the class.  Then whatever class method wants to create 
these items can simply append them to the list.


At this point, you should write some code, and it'll either work, or 
you'll tell us what part of it you can't understand.


--

DaveA

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


[Tutor] Class Nesting

2012-02-06 Thread Greg Nielsen
Hello List,

 My name is Greg, and while working on a project I've come across a
rather interesting problem. I'm trying to create a rough model of a star
cluster and all of the stars and planets contained within. Kind of a cool
project; hopefully it should work a little like this. I create a Star
Cluster object, which goes through a list of positions and decides if it
should build a Star System there. If it does, it then creates a Star System
object at that position which in turn calls upon and creates several Planet
objects to reside inside of it. All in all, about 64 positions to check, on
average 24 Star Systems, each with between 2 and 9 planets.
 So here is the problem, to create an object, you need to assign it to
a variable, and you need to know what that variable is to call upon it
later, so to have a object build a second object, it would need to somehow
create a variable name, and you would somehow have to know what name it
picked. Unless perhaps you had a Star Cluster list which had all of your
created Star System objects, each with their own list of Planets which you
could use list to call upon maybe
 I have a general grasp on the idea of nesting and calling upon objects
which you don't know the name of, but this goes far beyond my level of
understanding. Can anyone shed some light on how this would work, or
perhaps point me in the right direction of some documentation on this?
Thanks for the help, and I hope this is not too difficult of a question.

Greg
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class vs. instance

2012-01-18 Thread Alan Gauld

On 18/01/12 02:13, Stayvoid wrote:


class A:
def __init__(self, data):
self.data = data
print self.data

I'm trying to understand this function-like syntax:
A('foo').__init__(42)


You would not normally call any method with a double underscore 
pre/poist fix because they are special methods called by Python

itself. Thus when you do

A('foo')

Python actually calls two special methods on class A. First it calls the 
__new__() method to create an instance of A then it calls __init__() 
with 'foo' as argument to initialise that instance. You don't need to 
call init() directly. In fact it may even cause problems if you 
initialise a class twice.


So when you do

A('foo').__init__(42)

You actually do 3 things:
First you create a new instance of A, then you initialise it with 'foo' 
then you initialise it again with 42. In this case no harm is done 
because the init)() method just does a double assignment, losing the 
initial value. But if you were storing the data values in a lkist you 
would wind up with two values instead of one, which may not be a good thing.



A(12).data


Here you create another instance of A and initialise it with 12 then you 
access its data attribute. If you do this in the interpreter the value 
of data will be printed, if you do it in a program nothing will happen.


In both iof the cases above the newly created instances will be garbage 
collected since they were not assigned to any variable.



What are we actually calling this way?


You call the constructor __new__(), the initialiser __init__()
and you access a data item which calls the accessor __getattr__()


Are there any other ways to get the same result?


It depends how you define 'the same results'.
The same end state can be achieved in several ways.
The same methods can be called in several ways, for example
you can call init via the class:

anAinstance = A('foo')
A.__init__(anAinstance, 42)

But in general all of these are a bad idea outside of
a class/method definition. Don't do it.

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class vs. instance

2012-01-17 Thread Dave Angel

On 01/17/2012 09:13 PM, Stayvoid wrote:

Hello!

Here is another one.

class A:
def __init__(self, data):
self.data = data
print self.data

I'm trying to understand this function-like syntax:
A('foo').__init__(42)
A(12).data

What are we actually calling this way?
Are there any other ways to get the same result?
The first line creates an instance of class A, then immediately calls 
the method __init__() as though it were a normal function.  It then 
discards the object.


You should only call __init__() from within another class' __init__().  
It's called automatically when an object is created;  leave it at that.


You also usually want to keep the instance around, and use it more than 
once.  Otherwise you could just use ordinary functions and dispense with 
the confusion.


A(12) creates an object, then you reference the data attribute of that 
object, then you throw them both out.  Not much use there either.


Try  something like:

obj= A(49)
print obj.data
obj2 = A("artichoke")
obj.data = 99
print obj.data
print obj2.data

Two more things.  Remove the print statement from methods like 
__init__(), unless it's just for debugging purposes.  And add a base 
class of object to your class definition, so that a new-style class is 
created.  When you get to more advanced usage, it'll make a difference, 
and you might as well use the version of class that'll still work in 
Python 3.x.


class A(object):
 .



--

DaveA

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class vs. instance

2012-01-17 Thread Stayvoid
Hello!

Here is another one.

class A:
def __init__(self, data):
self.data = data
print self.data

I'm trying to understand this function-like syntax:
A('foo').__init__(42)
A(12).data

What are we actually calling this way?
Are there any other ways to get the same result?


Cheers.
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class vs. instance

2012-01-01 Thread Stayvoid
Thanks.

I totally get it now.
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class vs. instance

2012-01-01 Thread Hugo Arts
On Sun, Jan 1, 2012 at 8:40 PM, Stayvoid  wrote:
> Hi there!
>
 class Sample:
     def method(self): pass
>
 Sample().method()
>
> What's the difference between class __main__.Sample and
> __main__.Sample instance?
> Why should I write "Sample().method" instead of "Sample.method"?
>

The difference can be illustrated as such:

>>> Sample().method
>
>>> Sample().method()
>>> Sample.method

>>> Sample.method()
Traceback (most recent call last):
  File "", line 1, in 
TypeError: unbound method method() must be called with Sample instance
as first argument (got nothing instead)
>>>

That is, the difference between the methods is that the accessed
through the instance is also attached to that instance. It will
automagically get Sample() passed to it as its first argument (that
would be self). The one attached to the class is unbound, which means
that you can do this:

>>> Sample.method(Sample())
>>>

With any Sample instance, of course. This exposes a bit of syntax
sugar in python and how classes are really implemented, essentially
the fact that, if "a" is a sample instance, a.method(arg1, arg2, arg3)
is actually just Sample.method(a, arg1, arg2, arg3)

HTH,
Hugo
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


[Tutor] Class vs. instance

2012-01-01 Thread Stayvoid
Hi there!

>>> class Sample:
>>> def method(self): pass

>>> Sample().method()

What's the difference between class __main__.Sample and
__main__.Sample instance?
Why should I write "Sample().method" instead of "Sample.method"?


Cheers!
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class methods

2011-06-27 Thread Alan Gauld

"David Merrick"  wrote


Is it possible too have

crit1 = Critter("Dave")
crit2 = Critter("Sweetie")
farm = [crit1,crit2]  #List#

and then be able to use Critters methods on farm?


No, Marc has already answered that.


class Critter(object):

   """A virtual pet"""
   def __init__(self, name, hunger = 0, boredom = 0):

   # __ denotes private method
   def __pass_time(self):
   self.hunger += 1
   self.boredom += 1
   self.__str__()

   def __str__(self):
   print("Hunger is",self.hunger, "Boredom is " ,self.boredom)
   print("Unhappines is ",self.hunger + self.boredom," and Mood 
is

",self.mood)



This is a really bad idea. Please do not do this,
it will almost certainly lead to problems later.
__str__ should return a string. It should not print anything.

Then you can simply call

print (self)

at the end of the pass_time method

or call

print (farm[0])

in your external code.

HTH,


--
Alan Gauld
Author of the Learn to Program web site
http://www.alan-g.me.uk/


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class methods

2011-06-26 Thread Marc Tompkins
On Sun, Jun 26, 2011 at 7:12 PM, David Merrick  wrote:

> Is it possible too have
>
> crit1 = Critter("Dave")
> crit2 = Critter("Sweetie")
> farm = [crit1,crit2]  #List#
>
> and then be able to use Critters methods on farm?
>
> No.  farm is a list, and lists don't inherit the methods of the objects
inside them (imagine what a nightmare _that_ would be, especially since
lists can contain more than one type of object at any given time!)

Instead, you would refer to the members of the list:
farm[0].talk()
farm[1].talk()
etc.  Only you wouldn't generally hard-code those numbers; instead, you
could use the "for x in y" style:
for monster in farm:
monster.talk()
At this point, "monster" is one of your Critters.  When I need a looping
variable for a collection of custom objects, I like to use words that are
synonymous with, or at least related to, the name of my custom class.  It
helps me keep track of what's going on - if I use x and y all over the
place, I tend to get confused.

You could also use a more traditional, less-Pythonic approach:
for x in len(farm):
farm[x].talk()
But seriously, why would you want to use Python to imitate Visual Basic?

By the way, you shouldn't ever need to refer to Dave and Sweetie by their
hard-coded variable names, so instead of instead of creating "crit1, crit2",
why not simply create them as members of the list?
farm = []
for critter_name in ["Dave", "Sweetie"]:
farm.append(Critter(critter_name))
Now the variables don't have names per se, but you can still refer to them
by number if you need one in particular, or you can just loop over the list
with "for monster in farm".

Finally, maybe a dictionary would be more useful/intuitive than a list?
farm = []
for critter_name in ["Dave", "Sweetie"]:
farm[critter_name] = Critter(critter_name)
farm["Dave"].talk()

I do think that "farm" is going to be a little misleading as a name for a
collection of Critters; might I suggest "herd" or "swarm"?  Just a
thought...
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


[Tutor] Class methods

2011-06-26 Thread David Merrick
Is it possible too have

crit1 = Critter("Dave")
crit2 = Critter("Sweetie")
farm = [crit1,crit2]  #List#

and then be able to use Critters methods on farm?

# Critter Caretaker
# A virtual pet to care for

class Critter(object):

"""A virtual pet"""
def __init__(self, name, hunger = 0, boredom = 0):
self.name = name
self.hunger = hunger
self.boredom = boredom

# __ denotes private method
def __pass_time(self):
self.hunger += 1
self.boredom += 1
self.__str__()

def __str__(self):
print("Hunger is",self.hunger, "Boredom is " ,self.boredom)
print("Unhappines is ",self.hunger + self.boredom," and Mood is
",self.mood)



@property
def mood(self):
unhappiness = self.hunger + self.boredom
if unhappiness < 5:
m = "happy"
elif 5 <= unhappiness <= 10:
m = "okay"
elif 11 <= unhappiness <= 15:
m = "frustrated"
else:
m = "mad"
return m

def talk(self):
print("I'm", self.name, "and I feel", self.mood, "now.\n")
self.__pass_time()


def eat(self):
food = int(input("Enter how much food you want to feed your critter:
"))
print("Brruppp.  Thank you.")
self.hunger -= food
# hunger = 0 at iniatition
# self.hunger = self.boredom - food
if self.hunger < 0:
self.hunger = 0
self.__pass_time()


def play(self):
fun = int(input("Enter how much fun you want your critter to have:
"))
print("Wheee!")
self.boredom -= fun
# boredom = 0 at iniatition
# self.boredom = self.boredom - fun
if self.boredom < 0:
self.boredom = 0
self.__pass_time()


def main():
crit_name = input("What do you want to name your critter?: ")
crit = Critter(crit_name)

choice = None
while choice != "0":
print \
("""
Critter Caretaker

0 - Quit
1 - Listen to your critter
2 - Feed your critter
3 - Play with your critter
""")

choice = input("Choice: ")
print()

# exit
if choice == "0":
print("Good-bye.")

# listen to your critter
elif choice == "1":
crit.talk()

# feed your critter
elif choice == "2":
crit.eat()

# play with your critter
elif choice == "3":
crit.play()

# some unknown choice
else:
print("\nSorry, but", choice, "isn't a valid choice.")

main()
("\n\nPress the enter key to exit.")



-- 
Dave Merrick

merrick...@gmail.com

Ph   03 3423 121
Cell 027 3089 169
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class methods

2011-06-22 Thread Alan Gauld


"David Merrick"  wrote


Can someone show me how to code this correctly please?


We've been doing that but you are still making
some very basic mistakes which reflect a deep
misunderastanding of what you are doing. You
really should take several steps back and review
the use of variables and functions and then
reread the introductory material on classes
and objects. Until you get the basics right you
will struggle and even if somebody fixes all the
issues in this code, the minute you try another
program all the same problems will bite you.

That having been said I'll make some comments:


class Critter(object):

   """A virtual pet"""
   def __init__(self, name, hunger = 0, boredom = 0):
   self.name = name
   self.hunger = hunger
   self.boredom = boredom


This is OK.


   # __ denotes private method
   def __pass_time(self):
   self.hunger += 1
   self.boredom += 1
   self.__str__()


The last line does nothing useful. (It prints stuff just now
but that's because of a conceptual fault in your str method.
What you should really be saying here is:

print (self)


   def __str__(self):
   print("Hunger is",self.hunger, "Boredom is " ,self.boredom)
   print("Unhappines is ",self.hunger + self.boredom," and Mood 
is

",self.mood)


__str__ methods are supposed to return a string which
can be used (or printed) by other code. They should not
print anything themselves.

This should do something like:

return """Hunger is %s,
  Boredom is %s
  Unhappines is %s and
  Mood is%s""" % ( self.hunger,
  self.boredom,
  self.hunger+self.boredom,
  self.mood)


   @property
   def mood(self):
   unhappiness = self.hunger + self.boredom
   if unhappiness < 5:
   m = "happy"
   elif 5 <= unhappiness <= 10:
   m = "okay"
   elif 11 <= unhappiness <= 15:
   m = "frustrated"
   else:
   m = "mad"
   return m


OK


   def talk(self):
   for critter in farmlet:
   print("I'm", self.name, "and I feel", self.mood, 
"now.\n")

   self.__pass_time()


Problem: What is farmlet here? There is no farmlet in
the method. There is no self.farmlet you can access.
So now your class is tied to the external farmlet variable
in the global scope, making your class pretty much useless
in any other context. Also it will print the same message
as many times as there are critters in farmlet - 2 in this case.
But the message won't change because self still only
applies to the current object.

You are iterating over the critters in your main() function,
you don't need to do it inside the critter itself. Each critter
should only comment on its own state.

I'd also prefer that this returned a string too because
putting print statements inside methods limits the usefulness
of the class. How would it work in a GUI version for example?
Better to return a string and print that where you call it.


   def eat(self):
   food = int(input("Enter how much food you want to feed your 
critter:

"))
   print("Brruppp.  Thank you.")
   self.hunger -= food
   # hunger = 0 at iniatition
   # self.hunger = self.boredom - food
   if self.hunger < 0:
   self.hunger = 0
   self.__pass_time()


OK, I think


   def play(self):
   fun = int(input("Enter how much fun you want your critter to 
have:

"))
   print("Wheee!")
   self.boredom -= fun
   # boredom = 0 at iniatition
   # self.boredom = self.boredom - fun
   if self.boredom < 0:
   self.boredom = 0
   self.__pass_time()


OK, I think


def main():
   crit1 = Critter("Sweetie")
   crit2 = Critter("Dave")
   farmlet = [crit1,crit2]


OK so far, we have a list with two Critters


   choice = None
   while choice != "0":
   print \
   ("""
   Critter Caretaker

   0 - Quit
   1 - Listen to your critter
   2 - Feed your critter
   3 - Play with your critter
   """)

   choice = input("Choice: ")
   print()


Also OK we now have a choice and a loop.


   if choice == "0":
   print("Good-bye.")


And we exit so the program eventually stops,
which is good.


   elif choice == "1":
   for critter in farmlet:
   farmlet.talk()


But here we are asking the list to do stuiff which
is not good. It is the critters that talk. So you need
to send talk() to the critter not the list:

for critter in farmlet:
 critter.talk()


   # feed your critter
   elif choice == "2":
   farmlet.eat()


Again lists can't eat, you need to feed weither an
individual crittter - get the user to choose which?
- or feed all your critters using the same code
pattern as for talk above.


   # play with your critter
   elif choice == "3":
   f.play(farmlet)


You don't have an f and you don't now ha

Re: [Tutor] Class methods

2011-06-22 Thread Alan Gauld


"michael scott"  wrote 

you are using python 3 by your print statements, so I 
don't think you need the int() around your input, 


Yes he does because in Python 3 input is the same as raw_input 
in Python 2


even in python.2x input() was safe for numbers I believe 
(the whole list will rip my throat out if I'm wrong anyways


rip, rip, rip. :-)
In Python 2 input could be used for numbers but it was 
not "safe", which is why input was effectively removed 
in Python 3 and raw_input renamed to input. In Python 2 
input() evaluated whatever was typed as a Python expression 
which made it very unsafe. 



--
Alan Gauld
Author of the Learn to Program web site
http://www.alan-g.me.uk/


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class methods

2011-06-22 Thread michael scott
Just to add a little to Alexandre's answer.  You can keep most of the code the 
same just add in   
    farmlet[0].eat()
    farmlet[1].eat()

and it will be okay... kinda. Or you could rewrite it and  do it another 
way...  I'm guessing that you are using python 3 by your print statements, so I 
don't think you need the int() around your input, even in python.2x input() was 
safe for numbers I believe (the whole list will rip my throat out if I'm wrong 
anyways, lol), but in your while loop around line 82 you have all the 
conditions responding to a string, even thought you explicitly changed the 
input to an integer.

if choice == "0"


instead of 


if choice == 0:

so I got a continual output of 
('\nSorry, but', 3, "isn't a valid choice.")  

Now this does not get your program running the way you want it to, but it will 
start you off making the corrections you need. Just some things to think about, 
in line 113, when did you define class f?
in line 102, what are you trying to do, and are you telling it the right thing?
since you have 2 (or possibly more) critters you are taking care of, how does 
the player know which one he is feeding / talking to / playing with in your 
farmlet?

Anyways best of luck in your program, sounds pretty cool...

 

What is it about you... that intrigues me so?



From: Alexandre Conrad 
To: David Merrick 
Cc: tutor@python.org
Sent: Wednesday, June 22, 2011 6:48 PM
Subject: Re: [Tutor] Class methods

David,

2011/6/22 David Merrick :
>     # listen to your critter
>     elif choice == "1":
>     for critter in farmlet:
>     farmlet.talk()

You want to call .talk() on your "critter" instance which has the
.talk() method, not on farmlet (which is a list as the error message
states)

> Traceback (most recent call last):
>   File "I:/Python/programs/critter_farm4.py", line 117, in 
>     main()
>   File "I:/Python/programs/critter_farm4.py", line 103, in main
>     farmlet.talk()
> AttributeError: 'list' object has no attribute 'talk'

You will probably have a problem when calling talk() because it
references to the "farmlet" variable which doesn't exist in the scope
of your .talk() method.

HTH,
-- 
Alex | twitter.com/alexconrad
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class methods

2011-06-22 Thread Alexandre Conrad
David,

2011/6/22 David Merrick :
>     # listen to your critter
>     elif choice == "1":
>     for critter in farmlet:
>     farmlet.talk()

You want to call .talk() on your "critter" instance which has the
.talk() method, not on farmlet (which is a list as the error message
states)

> Traceback (most recent call last):
>   File "I:/Python/programs/critter_farm4.py", line 117, in 
>     main()
>   File "I:/Python/programs/critter_farm4.py", line 103, in main
>     farmlet.talk()
> AttributeError: 'list' object has no attribute 'talk'

You will probably have a problem when calling talk() because it
references to the "farmlet" variable which doesn't exist in the scope
of your .talk() method.

HTH,
-- 
Alex | twitter.com/alexconrad
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


[Tutor] Class methods

2011-06-22 Thread David Merrick
Can someone show me how to code this correctly please?

# Critter Caretaker
# A virtual pet to care for

class Critter(object):

"""A virtual pet"""
def __init__(self, name, hunger = 0, boredom = 0):
self.name = name
self.hunger = hunger
self.boredom = boredom

# __ denotes private method
def __pass_time(self):
self.hunger += 1
self.boredom += 1
self.__str__()

def __str__(self):
print("Hunger is",self.hunger, "Boredom is " ,self.boredom)
print("Unhappines is ",self.hunger + self.boredom," and Mood is
",self.mood)



@property
def mood(self):
unhappiness = self.hunger + self.boredom
if unhappiness < 5:
m = "happy"
elif 5 <= unhappiness <= 10:
m = "okay"
elif 11 <= unhappiness <= 15:
m = "frustrated"
else:
m = "mad"
return m

def talk(self):
for critter in farmlet:
print("I'm", self.name, "and I feel", self.mood, "now.\n")
self.__pass_time()


def eat(self):
food = int(input("Enter how much food you want to feed your critter:
"))
print("Brruppp.  Thank you.")
self.hunger -= food
# hunger = 0 at iniatition
# self.hunger = self.boredom - food
if self.hunger < 0:
self.hunger = 0
self.__pass_time()


def play(self):
fun = int(input("Enter how much fun you want your critter to have:
"))
print("Wheee!")
self.boredom -= fun
# boredom = 0 at iniatition
# self.boredom = self.boredom - fun
if self.boredom < 0:
self.boredom = 0
self.__pass_time()


##class Farm(Critter):
##def __init__(self,farmlet):
##   Critter.__init__(self,farmlet)
##   self.farmlet = farmlet
##
##def talk(self,farmlet):
##for critter in farmlet:
##print("Hello")
##Critter.talk(farmlet)

def main():
crit1 = Critter("Sweetie")
crit2 = Critter("Dave")
farmlet = [crit1,crit2]


choice = None
while choice != "0":
print \
("""
Critter Caretaker

0 - Quit
1 - Listen to your critter
2 - Feed your critter
3 - Play with your critter
""")

choice = input("Choice: ")
print()

# exit
if choice == "0":
print("Good-bye.")

# listen to your critter
elif choice == "1":
for critter in farmlet:
farmlet.talk()

# feed your critter
elif choice == "2":
farmlet.eat()

# play with your critter
elif choice == "3":
f.play(farmlet)

# some unknown choice
else:
print("\nSorry, but", choice, "isn't a valid choice.")

main()
("\n\nPress the enter key to exit.")

*Output*

Critter Caretaker

0 - Quit
1 - Listen to your critter
2 - Feed your critter
3 - Play with your critter

Choice: 1

Traceback (most recent call last):
  File "I:/Python/programs/critter_farm4.py", line 117, in 
main()
  File "I:/Python/programs/critter_farm4.py", line 103, in main
farmlet.talk()
AttributeError: 'list' object has no attribute 'talk'

-- 
Dave Merrick

merrick...@gmail.com

Ph   03 3423 121
Cell 027 3089 169
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class methods

2011-06-22 Thread Alan Gauld
"David Merrick"  wrote 


class Critter(object):

   def __init__(self, name, hunger = 0, boredom = 0):
   def __pass_time(self):
   def __str__(self):
   @property
   def mood(self):
   def talk(self):
   def eat(self):
   def play(self):

class Farm(Critter):


I still don't think a Farm is a type of Critter...


   def __init__(self,farmlet):
  Critter.__init__(self,farmlet)


This will set the name to farmlet, which I don't 
think you want.



   def talk(self,farmlet):


You don't need to pass farmlet in since the 
class has farmlet stored inside it. 
You can access farmlet with self.farmlet.



   for critter in farmlet:
   print("Hello")
   Critter.talk(farmlet)


You want the instance to talk not the class.
So you need to use critter.talk() And the talk 
method does not take any arguments except 
self. What you are doing here is calling the 
class method with an instance value of farmlet.

ie self in that method gets the value of farmlet.


def main():
   crit1 = Critter("Sweetie")
   crit2 = Critter("Dave")
   farmlet = [crit1,crit2]
   f = Farm(farmlet)

   choice = None
   while choice != "0":
   print \
   ("""
   Critter Caretaker

   0 - Quit
   1 - Listen to your critter
   2 - Feed your critter
   3 - Play with your critter
   """)

   choice = input("Choice: ")
   print()

   # exit
   if choice == "0":
   print("Good-bye.")

   # listen to your critter
   elif choice == "1":
   f.talk(farmlet)

   # feed your critter
   elif choice == "2":
   f.eat(farmlet)


Note that f.eat is a method you inherit from Critter.
The Critter method does not take any arguments 
so this will fail.



   # play with your critter
   elif choice == "3":
   f.play(farmlet)


Same with f.play()


Traceback (most recent call last):
 File "D:/David/Python/programs/critter_farm3.py", line 72, in talk
   Critter.talk(farmlet)
 File "D:/David/Python/programs/critter_farm3.py", line 38, in talk
   print("I'm", self.name, "and I feel", self.mood, "now.\n")
AttributeError: 'list' object has no attribute 'name'


This is because you are accessing the method via 
the class and passing farmlet as the instance value
rather than sending the message to the innstance 
directly. Use


critter.talk()   # and no farmlet needed! 


HTH,


--
Alan Gauld
Author of the Learn to Program web site
http://www.alan-g.me.uk/


___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


[Tutor] Class methods

2011-06-21 Thread David Merrick
# Critter Caretaker
# A virtual pet to care for

class Critter(object):

"""A virtual pet"""
def __init__(self, name, hunger = 0, boredom = 0):
self.name = name
self.hunger = hunger
self.boredom = boredom

# __ denotes private method
def __pass_time(self):
self.hunger += 1
self.boredom += 1
self.__str__()

def __str__(self):
print("Hunger is",self.hunger, "Boredom is " ,self.boredom)
print("Unhappines is ",self.hunger + self.boredom," and Mood is
",self.mood)



@property
def mood(self):
unhappiness = self.hunger + self.boredom
if unhappiness < 5:
m = "happy"
elif 5 <= unhappiness <= 10:
m = "okay"
elif 11 <= unhappiness <= 15:
m = "frustrated"
else:
m = "mad"
return m

def talk(self):
print("I'm", self.name, "and I feel", self.mood, "now.\n")
self.__pass_time()


def eat(self):
food = int(input("Enter how much food you want to feed your critter:
"))
print("Brruppp.  Thank you.")
self.hunger -= food
# hunger = 0 at iniatition
# self.hunger = self.boredom - food
if self.hunger < 0:
self.hunger = 0
self.__pass_time()


def play(self):
fun = int(input("Enter how much fun you want your critter to have:
"))
print("Wheee!")
self.boredom -= fun
# boredom = 0 at iniatition
# self.boredom = self.boredom - fun
if self.boredom < 0:
self.boredom = 0
self.__pass_time()


class Farm(Critter):
def __init__(self,farmlet):
   Critter.__init__(self,farmlet)
   self.farmlet = farmlet

def talk(self,farmlet):
for critter in farmlet:
print("Hello")
Critter.talk(farmlet)

def main():
crit1 = Critter("Sweetie")
crit2 = Critter("Dave")
farmlet = [crit1,crit2]
f = Farm(farmlet)

choice = None
while choice != "0":
print \
("""
Critter Caretaker

0 - Quit
1 - Listen to your critter
2 - Feed your critter
3 - Play with your critter
""")

choice = input("Choice: ")
print()

# exit
if choice == "0":
print("Good-bye.")

# listen to your critter
elif choice == "1":
f.talk(farmlet)

# feed your critter
elif choice == "2":
f.eat(farmlet)

# play with your critter
elif choice == "3":
f.play(farmlet)

# some unknown choice
else:
print("\nSorry, but", choice, "isn't a valid choice.")

main()
("\n\nPress the enter key to exit.")

*OUTPUT*

 Critter Caretaker

0 - Quit
1 - Listen to your critter
2 - Feed your critter
3 - Play with your critter

Choice: 1

Hello
Traceback (most recent call last):
  File "D:/David/Python/programs/critter_farm3.py", line 115, in 
main()
  File "D:/David/Python/programs/critter_farm3.py", line 101, in main
f.talk(farmlet)
  File "D:/David/Python/programs/critter_farm3.py", line 72, in talk
Critter.talk(farmlet)
  File "D:/David/Python/programs/critter_farm3.py", line 38, in talk
print("I'm", self.name, "and I feel", self.mood, "now.\n")
AttributeError: 'list' object has no attribute 'name'

I am trying to access Crit1 and Crit2 namr in farmlet
-- 
Dave Merrick

merrick...@gmail.com

Ph   03 3423 121
Cell 027 3089 169
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class question

2011-01-26 Thread ALAN GAULD


> >>I'm not sure I follow that  bit.
> 
> Say you have a master part, # 3245671, this is sort of a "primary  machined 
>number".  
>
> On the blueprint for this part, there will be certain  features that don't 
> have 
>any dimensional 
>
> information, but instead have a callout  of some kind, i.e., "Hole D", or 
>somesuch.  
>
> At the top of the blueprint is  a "tab block" that is a table of "alternate 
>part numbers", 
>

Ah OK, Yes I've seen that used in produccing similar but different printed 
circuit boards
(my background is in electronics not foundry work)

> This was originally a convenience/cost saving thing, I  suspect.  

Almost certainly, and it makes it much easier to add new variants since only 
the tab values need changing.

What it means for you is that you need in parallel to your main app a 
mechanism for managing the identities through these differeing ID values.
Effectively a lookup table and mechanism for tracing designs from raw 
pattern to finished item.

> >>You may also find it useful to think through the state  model for your 
> castings/workpieces. That may help to constrain the number of  
>Actions/operations required.
> 
> ummm...what's a "state model"?  

It defines what operations can be done on your objects at any given time 
depending on the "state" of the object. As a simple example a light can 
be switched on when it is off and off when it is on, but it cannot be 
switched off if it is already off. In your can you will have a sequence of 
operations with dependencies between them such that certain operations 
can only be done after others have completed. Others cannot be done 
after others have been done. State models can be table driven which 
makes them highly configurable so that a single object can be loaded by 
multiple state models and effectively act like different object types without 
having to change the code.

HTH,

Alan G.

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class question

2011-01-26 Thread Steven D'Aprano

Elwin Estle wrote:

--- On Wed, 1/26/11, Alan Gauld  wrote:

From: Alan Gauld 
Subject: Re: [Tutor] class question
To: tutor@python.org
Date: Wednesday, January 26, 2011, 1:10 PM

Is this really a series of different types of casting or a single Workpiece 
going through a sequence of Actions
each Action having a set of quality data associated?



If so it may be that you have a single Workpiece class and a relatively small 
heirarchy of Actions.


No, there are multiple castings, anywhere from smallish parts you can hold in 
the palm of your hand, up to engine blocks weighing nearly 2 tons.


Then each such casting has its own set of actions and chain of classes.

There is a process that goes from egg to chick to hen to KFC Chicken 
Nuggets, but you wouldn't write a single class to model all of those 
things. You would write a separate class for each distinct stage of the 
process, and write a process that replaces each data item with the next 
one in the series.


I think you are focused too heavily on the fact that it's the same lump 
of metal all the way through the pipeline. That's the least important 
part of the design -- you can do that with a simple record:


class Lump:
def __init__(self, id, kind):
self.id = id
self.obj = kind()

lumps = [
Lump(1, EngineBlockCasting),
Lump(2, EngineBlockCasting),
Lump(3, WidgetCasting),
Lump(4, MiniCasting),
... ]

and then later on:

lumps[1].obj = EngineBlockWithHolesDrilled()

Although of course you will write functions or methods to move from one 
class to another, e.g. drill_holes(lumps, 1), rather than do it all by hand.




--
Steven
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class Docs - how much is too much?

2011-01-26 Thread Tim Johnson
* Emile van Sebille  [110126 12:30]:
> On 1/26/2011 11:03 AM Tim Johnson said...
>>
>> I've developed a module which necessitates a very large amount of
>> documentation. At this point all of the documentation is in the
>> class docstring. I'm thinking that perhaps I should pare down the
>> docstring and deliver specific documentation topics with object
<<...>>
>> :) Perhaps there is a PEP for this and a link to such a PEP would
>> suffice.
>
> Yep -- google python pep docstring and you get
>
> http://www.python.org/dev/peps/pep-0257/
  Thank you. That's all I need.
-- 
Tim 
tim at johnsons-web.com or akwebsoft.com
http://www.akwebsoft.com
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] Class Docs - how much is too much?

2011-01-26 Thread Emile van Sebille

On 1/26/2011 11:03 AM Tim Johnson said...

FYI: I'm currently using version 2.6.5

I've developed a module which necessitates a very large amount of
documentation. At this point all of the documentation is in the
class docstring. I'm thinking that perhaps I should pare down the
docstring and deliver specific documentation topics with object
methods. Example:
## Instantiation examples
o.intialize()
## configuration code to copy and paste into file
o.configuration()
## Internal processes
o.internals()
## ... etc.
## Docstring would include instructions for implementing such
## methods.

:) Perhaps there is a PEP for this and a link to such a PEP would
suffice.


Yep -- google python pep docstring and you get

http://www.python.org/dev/peps/pep-0257/

Emile

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] class question

2011-01-26 Thread Elwin Estle

--- On Wed, 1/26/11, Alan Gauld  wrote:

From: Alan Gauld 
Subject: Re: [Tutor] class question
To: tutor@python.org
Date: Wednesday, January 26, 2011, 1:10 PM
>>Is this really a series of different types of casting or a single Workpiece 
>>going through a sequence of Actions
>>each Action having a set of quality data associated?

>>If so it may be that you have a single Workpiece class and a relatively small 
>>heirarchy of Actions.

No, there are multiple castings, anywhere from smallish parts you can hold in 
the palm of your hand, up to engine blocks weighing nearly 2 tons.

>>Is it the casting or the machining that has the quality related data? ie Is 
>>it casting specific or operation specific?

The casting can have quality data associated with it, tho rarely.  If there is 
a machining issue that can be traced back to defective castings, then yes (but 
we don't really have any process in place for this, normally that sort of thing 
is the casting supplier's problem).  Normally, tho, it is the machining that 
has the associated quality data., i.e., measure a 2.500 machined bore with a 
+/- .001 tolerance, using such and such gage, giving some result (like 2.503, 
for example), measured on such and such date by such and such machine operator. 
 Various bits like this will be associated with a given machining operation.  
Sometimes machining operations are all done on a single machine, sometimes they 
span multiple machines.

>>Do you know in advance what these operations will be? Can you assign a 
>>WorkPlan to the Workpiece? Each step of the plan having an associated Action?

I would say yes.  However, and this ties in with something you ask further 
down, sometimes that plan may sort of "overlap"  For example, say we have a raw 
casting, 3402963R, that when machined, becomes part # 3402963.  But that same 
raw casting may also be machined into another part number # 3332965, simply by 
adding or omitting hole or some other feature.  So, I suppose one could have 
separate plans for each finished part number, in which case there might be some 
duplication of things for each plan.

> Each of those operations on separate machines will have a different set of 
> quality checks associated with it.

So here we clearly say it is the Action that has the data associated...

> ...or it might be a part that goes from a raw casting to a sort of 
> "mini-assembly" such as a rocker lever ...
> but it is still the same thing, and each one of those steps may have some 
> sort of quality check involved.

So a workpice can consist of other WorkPieces.
And again tyhe Actions associated have quality data

>>> Lets complicate things even further. One raw casting may be machined into 
>>> multiple part numbers.

>>Is that true? Or is it one type of casting?
>>Each instance of casting will surely onmly go through one specific set of 
>>actions? If we treat them all as generic >>workpieces then the Actions are 
>>different but the workpiece concept remains constant?

>>Or, are we saying that a single original workpiece can be cut into several 
>>distinct workpieces? Again thats not >>necessarily a problem, objects can 
>>clone themselves and have the clones diverge thereafter.

Yes, that is the case, as described above.

>>> This is done through something called a "tabbed" blueprint, wherein there 
>>> is a master number, but there are "tabs" indicating that if you changes 
>>> such and such feature, then the part number isn't the master number, but 
>>> the tabbed number.

>>I'm not sure I follow that bit.

Say you have a master part, # 3245671, this is sort of a "primary machined 
number".  On the blueprint for this part, there will be certain features that 
don't have any dimensional information, but instead have a callout of some 
kind, i.e., "Hole D", or somesuch.   At the top of the blueprint is a "tab 
block" that is a table of "alternate part numbers", vs these "named features".  
Each of these part numbers will have differing information as to the nature of 
"Hole D".  Perhaps the size of "Hole D" differs from one part number to the 
next, or perhaps it is omitted all together.  It goes along wth the "one 
casting makes multiple part numbers" thing described above.  In and of itself, 
this perhaps may not seem that complicated...but the blueprints aren't filed 
under the the actual part number for a given tabbed part, but under the master 
number.  So...you may have part 3458760, but the blueprint for it is filed 
under 3245671, so you have to go hunt up that
 blueprint, then hunt up the information on it that describes the actual part 
in question.  All this ties in to your qual

  1   2   3   4   5   >