Declaring class object datatypes - python

I have a class Foo which contains a datamember of type Bar. I can't make a generalized, "default" Bar.__init__() - the Bar object is passed into the Foo.__init__() method.
How do I tell Python that I want a datamember of this type?
class Foo:
# These are the other things I've tried, with their errors
myBar # NameError: name 'myBar' is not defined
Bar myBar # Java style: this is invalid Python syntax.
myBar = None #Assign "None", assign the real value in __init__. Doesn't work
#####
myBar = Bar(0,0,0) # Pass in "default" values.
def __init__(self, theBar):
self.myBar = theBar
def getBar(self):
return self.myBar
This works, when I pass in the "default" values as shown. However, when I call getBar, I do not get back the one I passed in in the Foo.__init__() function - I get the "default" values.
b = Bar(1,2,3)
f = Foo(b)
print f.getBar().a, f.getBar().b, f.getBar().c
This spits out 0 0 0, not 1 2 3, like I'm expecting.
If I don't bother declaring the myBar variable, I get errors in the getBar(self): method (Foo instance has no attribute 'myBar').
What's the correct way to use a custom datamember in my object?

You don't need to tell Python you are going to add a certain data member – just add it. Python is more dynamic than e.g. Java in this regard.
If bar instances are essentially immutable (meaning they are not changed in practice), you can give the default instance as default value of the __init__() parameter:
class Foo:
def __init__(self, the_bar=Bar(0,0,0)):
self.my_bar = the_bar
All Foo instances uisng the default value will share a single Bar instance. If the Bar instance might be changed, this is probably not what you want, and you should use this idiom in this case:
class Foo:
def __init__(self, the_bar=None):
if the_bar is None:
the_bar = Bar(0,0,0)
self.my_bar = the_bar
Note that you shouldn't usually write getters and setters in Python. They are just unnecessary boilerplate code slowing down your application. Since Python supports properties, you also don't need them to be future-proof.

The correct way is to do nothing other than assign it in the constructor.
class Foo:
def __init__(self, bar):
self.bar = bar
def getbar(self):
return self.bar

You definitely don't have to declare bar ahead of time.
It sounds like you want Foo.bar to default to a value if one isn't specified so you might do something like this:
class Foo:
def __init__(self, bar=None):
# one of many ways to construct a new
# default Bar if one isn't provided:
self._bar = bar if bar else Bar(...)
#property
def bar(self):
"""
This isn't necessary but you can provide proper getters and setters
if you prefer.
"""
return self._bar
#bar.setter
def bar(self, newbar):
"""
Example of defining a setter
"""
return self._bar = newbar
Typically just naming the variable appropriately and omitting the setter is considered more more 'pythonic'.
class Foo:
def __init__(self, bar=None):
self.bar = bar if bar else Bar(...)

You don't declare variables in Python, and variables are untyped.
Just do:
class Foo(object):
def __init__(self, bar):
self.bar = bar
def getbar(self):
return self.bar
I suspect that the issue is caused by you using old-style classes, which are kind of odd. If you inherit from object, you get a new-style class, which is designed to be much less surprising.

Related

How to get class of object being created in __init__ parameters

So I am trying to create a class with an initialization method that needs to get the type of the object being created in order to properly set the default values of the init arguments.
To give a concrete example with code, say I have the following class:
def __init__(self, foo, bar=type(self).some_class_variable, ham=type(self).some_other_class_variable):
self.foo = foo
self.bar = bar
self.ham = self.some_function(ham)
This is the functionality I am looking for, but my IDE is saying "self" is not defined which I can understand, as self has yet to be instantiated. So my question is how would I go about implementing this properly? I do not want to "hardcode" the class type in where I currently have type(self) because subclasses of this class may have their own values for some_class_variable and some_other_class_variable and I want those subclasses to use the class variable corresponding to their type.
My solution needs to work in Python 3.6 & Python 3.7 but I would really prefer to find a solution that works in all versions of Python 3.6 and later if possible.
I think that you should put it in the body, not the parameter.
def __init__(self, foo):
self.foo = foo
self.bar = type(self).some_class_variable
self.ham = self.some_function(type(self).some_other_class_variable)
EDIT:
If the values are defaults, you can do this:
default_value = 'default pls'
def __init__(self, foo, bar=default_value, ham=default_value):
self.foo = foo
if default_value == bar:
self.bar = type(self).some_class_variable
if default_value == ham:
self.ham = self.some_function(type(self).some_other_class_variable)
The class name is not bound yet, as the class has not been initialised at that point. See this answer which explains this in more depth.
A way to work-around this, albeit not that great, is to create setter methods for the variables, and to set them after an instance has been initialised, like so:
class Example:
def __init__(self, foo):
self.foo = foo
self.bar = None
self.ham = None
def set_bar(self, bar):
self.bar = bar
def set_ham(self, ham):
self.ham = ham
You can go one step further to validate the type of those attributes with a simple if statement, or through python 'typing'.

After using property decorator, python object has two very similar attributes (foo.bar and foo._bar). Is that ok?

So I'm refactoring my code to be more Pythonic - specifically I've learned that using explicit getters and setters should be replaced with #property. My case is that i have an Example class with initialized bar attribute (initialization helps me to know that user set the bar):
class Example:
def __init__(self):
self.bar = 'initializedValue'
#property
def bar(self):
return self._bar
#bar.setter
def bar(self, b):
self._bar = b
def doIfBarWasSet():
if self.bar != 'initializedValue':
pass
else:
pass
after running foo = Example() my debugger shows that foo has two attributes: _bar and bar, both set to 'initializedValue'. Also, when I run foo.bar = 'changedValue' or foo._bar = 'changedValue', both of them are changed to 'changedValue'. Why there are two attributes? Isn't that redundant? I think I understand why there is _bar attribute - I added it in #bar.setter, but why there is bar as an string attribute? Shouldn't bar be rather a method leading to bar #property?
It's fine. Keep in mind that bar is not an instance attribute, but a class attribute. Since it has type property, it implements the descriptor protocol so that its behavior is different when accessed from an instance. If e is an instance of Example, then e.bar does not give you the instance of property assigned to Example.bar; it gives you the result of Example.bar.__get__(e, Example) (which in this case, happens to be Example.bar.fget(e), where fget is the original function decorated by #property).
In short, every instance has its own _bar attribute, but access to that attribute is mediated by the class attribute Example.bar.
It's easier to see that bar is a class attribute if you write this minimal (and sufficient, since neither the getter nor setter in this case requires a def statement) definition.
class Example:
def __init__(self):
self.bar = "initalizedValue"
bar = property(lambda self: self._bar, lambda self, b: setattr(self, '_bar', b))
or more generally
def bar_getter(self):
return self._bar
def bar_setter(self, b):
self._bar = b
class Example:
def __init__(self):
self.bar = "initalizedValue"
bar = property(bar_getter, bar_setter)

Differentiate accessing class attribute from within the class (or file) and from outside in python

Let us have an example class Foo in Python:
class Foo:
bar = 'bar'
def access_bar(self):
return self.bar
Can I, for example print a warning, when accessing Foo().bar directly, but at the same time not print this warning when calling Foo().access_bar(), which accesses that attribute from within the class?
I tried to implement __getattribute__ method, but with no luck with differentiating these cases.
I know it's quite a strange question, but please don't answer me like 'You should not need this'.
Here is the 'real' answer to your question, which you probably shouldn't do:
import inspect
class Foo:
bar = 'bar'
def access_bar(self):
return self.bar
def __getattribute__(self, item):
if item == 'bar':
code = inspect.currentframe().f_back.f_code
if not (start_lineno <= code.co_firstlineno <= end_lineno
and code.co_filename == __file__):
print('Warning: accessing bar directly')
return super().__getattribute__(item)
lines, start_lineno = inspect.getsourcelines(Foo)
end_lineno = start_lineno + len(lines) - 1
print(1, Foo().bar)
print(2, Foo().access_bar())
If you do this it's important that there's only one class named Foo in the file, otherwise inspect.getsourcelines(Foo) may not give the right result.
you could make bar a property which allows to control the access without showing the method call to the outside, and make your attribute private:
class Foo:
__bar = 'bar'
#property
def bar(self):
print("direct access")
return Foo.__bar
def access_bar(self):
return self.__bar
f = Foo()
print("warn",f.bar)
print("OK",f.access_bar())
prints:
direct access
warn bar
OK bar
I suggest storing the value in a protected (one leading underscore) or private (two underscores) attribute, and making bar a property that can be accessed safely, the equivalent of access_bar in your question. That's how this sort of thing is typically done in Python.
class Foo:
_bar = 'bar'
#property
def bar(self):
# do extra things here
return self._bar
A user can still write foo._bar or foo._Foo__bar (for a private attribute) to get the attribute externally without any warning, but if they are aware of the conventions surrounding leading underscores they will probably feel somewhat uncomfortable doing so and be aware of the risks.
Here's another attempt at improving Alex's answer by adding a metaclass so that it also works for class attributes, and doing away with inspect module, and instead add a warning flag to the __getattribute__ function itself.
class FooType(type):
def __getattribute__(self, item):
if item == "bar":
print("Warning: accessing bar directly from class")
return item.__getattribute__(self, item)
class Foo(object, metaclass=FooType):
bar = 'bar'
def access_bar(self):
return self.__getattribute__('bar', warn=False)
def __getattribute__(self, item, warn=True):
if item == 'bar' and warn:
print('Warning: accessing bar directly from instance')
return super().__getattribute__(item)
print(Foo.bar)
#Warning: accessing bar directly from class
#bar
print(Foo().bar)
#Warning: accessing bar directly from instance
#bar
print(Foo().access_bar())
#bar

How to override a method of a member object?

In python 3.4 I have a member object through composition.
I would like to override one of it's member functions.
def class Foo:
def __init__(self, value):
self.value = value
def member_obj.baz(baz_self, arg):
print("my new actions on {}".format(arg))
Foo.member_obj.baz(arg) #the original function
foo_inst = Foo(2)
bar = Bar(*bar_parameters) #from a third party module
setattr(foo_inst, "member_obj", bar) #it did not "stick" when I did foo_inst.member_obj = bar
foo_inst.member_obj.baz("some argument")
It does not make sense to inherit from the Bar class.
I also only want this different behaviour to occur if the object is inside Foo. I use Bar in many other places and would like to retain the same way of calling the method. I.e. I would like to avoid wrapping it in Foo.baz.
Is it even possible to do something like the def member_obj.baz and is it a good idea?
It would be similar to this: https://softwareengineering.stackexchange.com/questions/150973/what-are-the-alternatives-to-overriding-a-method-when-using-composition-instea
Are you trying to do something like this?
class B():
def __init__(self):
self.x = None
def fun(self):
print("Assigning value to attribute of object of class B.\n")
self.x = "Value of B object's attribute"
class A():
def __init__(self):
self.value = B()
def fun(self):
print("Screw this, I'll do something else this time!\n")
self.value.x = 13
def override(self):
# Edit: you can assign any identifier (that is not reserved) to
# any type of object or method AND the "fun" ("really self.fun")
# above is visible from here, since we passed "self" as an
# argument
self.value.fun = self.fun
myObj = B()
myOtherObj = A()
myOtherObj.override()
myObj.fun()
myOtherObj.value.fun()

Add attribute to python class

Consider the following code:
class Foo():
pass
Foo.entries = dict()
a = Foo()
a.entries['1'] = 1
b = Foo()
b.entries['3'] = 3
print(a.entries)
This will print:
{'1': 1, '3': 3}
because the entries is added as static attribute. Is there a way monkey patch the class definition in order to add new attributes (without using inheritance).
I managed to find the following way but it looks convoluted to me:
def patch_me(target, field, value):
def func(self):
if not hasattr(self, '__' + field):
setattr(self, '__' + field, value())
return getattr(self, '__' + field)
setattr(target, field, property(func))
patch_me(Foo, 'entries', dict)
Ordinarily, attributes are added either by the __init__() function or after instantiating:
foo = Foo()
foo.bar = 'something' # note case
If you want to do this automatically, inheritance is by far the simplest way to do so:
class Baz(Foo):
def __init__(self):
super().__init__() # super() needs arguments in 2.x
self.bar = 'something'
Note that classes don't need to appear at the top level of a Python module. You can declare a class inside a function:
def make_baz(value):
class Baz(Foo):
def __init__(self):
super().__init__() # super() needs arguments in 2.x
self.bar = value()
return Baz()
This example will create a new class every time make_baz() is called. That may or may not be what you want. It would probably be simpler to just do this:
def make_foo(value):
result = Foo()
result.bar = value()
return result
If you're really set on monkey-patching the original class, the example code you provided is more or less the simplest way of doing it. You might consider using decorator syntax for property(), but that's a minor change. I should also note that it will not invoke double-underscore name mangling, which is probably a good thing because it means you cannot conflict with any names used by the class itself.

Categories

Resources