What's the equivalent of Ruby's class ##variable in Python? - python

In Ruby 1.9, I can use its class variable like the following:
class Sample
##count = 0
def initialize
##count += 1
end
def count
##count
end
end
sample = Sample.new
puts sample.count # Output: 1
sample2 = Sample.new
puts sample2.count # Output: 2
How can I achieve the above in Python 2.5+ ?

class Sample(object):
_count = 0
def __init__(self):
Sample._count += 1
#property
def count(self):
return Sample._count
The use is a bit different from Ruby; e.g. if you have this code in module a.py,
>>> import a
>>> x = a.Sample()
>>> print x.count
1
>>> y = a.Sample()
>>> print x.count
2
having a Sample.count "class property" (with the same name as the instance property) would be a bit tricky in Python (feasible, but not worth the bother IMHO).

Related

Why does Pycharm Console do this with my __repr__ method?

class B:
def __init__(self):
print('boo!')
self.a = []
def __repr__(self):
print(len(self.a))
ret = ''
for a in self.a:
ret += str(a)
return ret
The following is copy pasted from the Pycharm Console using python 3.8.6 and IPython 7.31.0:
>>> b = B()
boo!
0
0
>> b
Out[4]: 0
0
0
0
0
0
0
0
0
0
0
>> 2 + 3
Out[5]: 5
0
0
0
0
0
0
0
0
0
0
This does not happen in python REPL or iPython running in the cmd (see comments).
Why is this happening?
You're only showing and using B in your code, so we'll use just that.
class B:
def __init__(self):
print('boo!')
self.a = []
def add_a(self, a):
self.a.append(a)
def __repr__(self):
print(len(self.a))
ret = ''
for a in self.a:
ret += str(a)
return ret
When you run just B() (a call expression), this is the sequence of things that happens (in python and ipython):
create new instance with __new__ (inherited from object)
initialise the instance with __init__, which prints boo! and sets the a attribute to an empty list []
display the instance you've just created with __repr__, which in your case:
prints 0, the length of a attribute
set a local ret variable to ''
iterates through the a attribute which is empty
returns returns '' from ret
However, step 3. applies only to running expressions B(), the python interactive shell runs the expression and displays their result.
The b = B() assignment statement should not trigger a "display result" event (and will not in python, IDLE or ipython).

Python - Log the things a string has previously been

If this is my code:
x = 1
x = 2
x = 3
How can I “log” the things x has been and print them? If my explanation was dumb, then here’s what I expect:
>>> # Code to print the things x has been
1, 2, 3
>>>
How can I achieve this?
Since assignment overwrites the value of the object (in your example 'x'), it is not possible to do exactly what you want. However, you could create an object, of which the value can be changed and its history remembered. For example like this:
#!/usr/bin/env/python3
class ValueWithHistory():
def __init__(self):
self.history = []
self._value = None
#property
def value(self):
return self._value
#value.setter
def value(self, new_value):
self.history.append(new_value)
self._value = new_value
def get_history(self):
return self.history
def clear_history(self):
self.history.clear()
def main():
test = ValueWithHistory()
test.value = 1
print(test.value)
test.value = 2
print(test.value)
test.value = 3
print(test.value)
print(test.get_history())
if __name__ == '__main__':
main()
This prints:
1
2
3
[1, 2, 3]
Of course, you could also use a set instead of a list to only remember each unique value once, for example.
You can order a second thread to observe the string and print the changes:
from threading import Thread
def string_watcher():
global my_string
global log
temp = ''
while True:
if my_string != temp:
log.append(my_string)
temp = my_string
t = Thread(target=string_watcher, daemon=True)
t.start()
This checks weather the string „my_string“ was manipulated and appends it to the list „log“, if it has been changed. With this you should be able to perform
Print(log)
At any moment of the runtime

Generating a protocol string

I'd like to read combined information from of a bunch of variables.
I tried this here:
class MyStruct:
first_byte = 0
second_byte = 0
combined = str(hex(first_byte)) + " " + str(hex(second_byte))
test = MyStruct() test.first_byte = 36 test.second_byte = 128
print("MyStruct: test first=%i second=%i comb=%s" %(test.first_byte, test.second_byte, test.combined))
And I get:
>
MyStruct: test first=36 second=128 comb=0x0 0x0
But I was expecting:
>
MyStruct: test first=36 second=128 comb=0x24 0x80
I see that the calculations of them combined are made just when it is declared. But I don't know how to calculate it again.
Why I am using this:
I'd like to create a protocol-string for LIN-signals over a CARBERRY
Here you can find further information: LIN-command
I'd like to define each byte separately like this:
protokol.pid = 10
protokol.D0 = value_one
protokol.D1 = value_two
and so on..
Well, simply put, the line combined = str(hex(first_byte)) + " " + str(hex(second_byte))
is evaluated when you create the class.
What you could do is the following:
class MyStruct:
def __init__(self, first_byte, second_byte):
self.first_byte = first_byte
self.second_byte = second_byte
self.combined = hex(first_byte) + " " + hex(second_byte)
test = MyStruct(36, 128)
print("MyStruct: test first=%i second=%i comb=%s" %(test.first_byte, test.second_byte, test.combined))
I suggest you take a look at classes, methods and attributes before you go any further, you may pick up a few useful tools.
Further explanation:
By declaring first_byte and second_byte directly inside the class, you are creating static class variables, accessed by MyStruct.first_byte and MyStruct.second_byte. Here's an example to illustrate what I'm talking about:
>>> class A:
tag = 10
def set_tag(self, val):
self.tag = val
>>> b = A()
>>> b.tag
10
>>> A.tag
10
>>> b.set_tag(5)
>>> b.tag
5
>>> A.tag
10

OOP python program

from collections import Counter
class Runlength:
def __init__(self):
self.str = 0
def returner(self,str):
self.str = str
self.__str = ','.join(str(n) for n in self.__str)
self.__str = self.__str[::-1]
self.__str = self.__str.replace(',', '')
return self.__str
def final(self,num):
self.num = num
k = []
c = Counter(self.num).most_common()
for x in c:
k += x
return k
math = Runlength()
def Main():
a = "aabbcc"
b = math.returner(a)
c = math.final(b)
print(c)
Main()
The program takes a word as input and gives the occurrence of each repeating character and
outputs that number along with a single character of the repeating sequence.
I cant figure it out, why this doesn't work. I get this error:
NameError: global name 'returner' is not defined
The problem is that in Main() you are not accessing the global (outside the scope of the Main() method) math variable. Instead try initializing your math inside the Main() function
This lets the method know that it should use the global math variable instead of trying to look for a non-existent local one.
I got this error with your code:
self.__str = ','.join(str(n) for n in self.__str)
AttributeError: Runlength instance has no attribute '_Runlength__str'
Maybe you mean:
self.__str = ','.join(str(n) for n in self.str
And choose input argument for returner() method as str_ not str, cause str -- is the name of python built-in type, so better to not choose variable names with built-in type names.
So after this changes I got this output:
['a', 2, 'c', 2, 'b', 2]
So my python version is 2.7.3 and error you've got does not appear with my python version.
What python version you use to compile your code? If this python3 it works fine too.So try this code, it works fine for me:
from collections import Counter
class Runlength:
def __init__(self):
self.str = 0
def returner(self,str_):
self.string = str_
self.__str = ','.join(str(n) for n in self.string)
self.__str = self.__str[::-1]
self.__str = self.__str.replace(',', '')
return self.__str
def final(self,num):
self.num = num
k = []
c = Counter(self.num).most_common()
for x in c:
k += x
return k
math = Runlength()
def Main():
a = "aabbcc"
b = math.returner(a)
c = math.final(b)
print(c)
Main()
def Main():
math = Runlength()
a = "aabbcc"
b = math.returner(a)
c = math.final(b)
print(c)
Main()
This should work fine..
But I observed that the object can even be accessed if it is not declared as global. Is their any explantion for it in the above scenario?

Python patch existing class

I'm an experienced PHP/Ruby developer but right now I'm fighting Python and I really need your help.
I need to patch existing class by adding static attribute and overwriting static function to use it.
Let me show you example:
class Test():
#staticmethod
def generate():
return 10
But in my test suite I need to get the following class:
class Test():
count = 1
#staticmethod
def generate():
if Test.count < 3:
Test.count += 1
return 1
else:
return 10
So the basic idea is to get 10 only on the 3rd call of "generate" function.
My first approach was to use "patch" technique, so I did:
def my_generate_hash():
return 99
with patch.object(Test, 'generate', staticmethod(my_generate_hash)):
print "Got %d" % check_hash()
Buuut I was unable to implement attribute "count" and use it in overriding method (
Second thought was to "Mock" something! So..
mock = MagicMock(Test)
mock.count = 1
def my_generate_hash():
if Test2.count < 3:
Test2.count += 1
return 1
else:
return 10
mock.generate = my_generate_hash
with patch('__main__.Test', mock):
print Test.generate()
But in real case I have other methods in "Test" class, so it won't work.
I'm stuck. Any help will be appreciated!
It might be simpler to subclass the original Test class for use in your tests:
class Test(object):
#staticmethod
def generate():
return 10
class PatchedTest(Test):
count = 1
#staticmethod
def generate():
if Test.count < 3:
Test.count += 1
return 1
else:
return 10
The replacement function could also be done in two somewhat better ways, both of which should make it a lot easier to patch the Test class in the same way you were trying in your question:
Use a #classmethod, allowing the function to access the class it's assigned to:
class PatchedTest(Test):
count = 1
#classmethod
def generate(cls):
if cls.count < 3:
cls.count += 1
return 1
else:
return 10
Use a generator instead - each time the function is called it will continue execution where it last left off. However, this will only work if you are iterating over the functions result:
def alternative_generate():
yield 1
yield 1
yield 10
Looks like in can be in a different way.
self.count = 0
def generate():
if self.count < 3
self.count += 1
return 10
else:
return 99
with patch.object(Test, 'generate', generate):
self.assertEqual(Test.generate(), 10)
self.assertEqual(Test.generate(), 10)
self.assertEqual(Test.generate(), 10)
self.assertEqual(Test.generate(), 99)
self.assertEqual(Test.generate(), 99)

Categories